Skip to content

Commit 6808057

Browse files
Rework the resolution slides + grammar checks
1 parent f3a7118 commit 6808057

File tree

5 files changed

+46
-27
lines changed

5 files changed

+46
-27
lines changed

src/SUMMARY.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -440,9 +440,9 @@
440440
- [Extension Traits](idiomatic/leveraging-the-type-system/extension-traits.md)
441441
- [Extending Foreign Types](idiomatic/leveraging-the-type-system/extension-traits/extending-foreign-types.md)
442442
- [Method Resolution Conflicts](idiomatic/leveraging-the-type-system/extension-traits/method-resolution-conflicts.md)
443+
- [Trait Method Conflicts](idiomatic/leveraging-the-type-system/extension-traits/trait-method-conflicts.md)
443444
- [Extending Other Traits](idiomatic/leveraging-the-type-system/extension-traits/extending-other-traits.md)
444445
- [Should I Define An Extension Trait?](idiomatic/leveraging-the-type-system/extension-traits/should-i-define-an-extension-trait.md)
445-
- [Trait Method Conflicts](idiomatic/leveraging-the-type-system/extension-traits/trait-method-conflicts.md)
446446

447447
---
448448

src/idiomatic/leveraging-the-type-system/extension-traits/extending-foreign-types.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ assert!(!"grandma".is_palindrome());
4848
that's emitted if you try to invoke an extension method without having the
4949
corresponding extension trait in scope.
5050

51-
- The example above uses an [_underscore import_][3] (`use ext::StrExt as _`) to
52-
minimize the likelihood of a naming conflict with other imported traits.
51+
- The example above uses an [_underscore import_][3] (`use ext::StringExt as _`)
52+
to minimize the likelihood of a naming conflict with other imported traits.
5353

5454
With an underscore import, the trait is considered to be in scope and you're
5555
allowed to invoke its methods on types that implement the trait. Its _symbol_,

src/idiomatic/leveraging-the-type-system/extension-traits/extending-other-traits.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ assert_eq!(true.quoted(), "'true'");
3232
<details>
3333

3434
- Highlight how we added new behavior to _multiple_ types at once. `.quoted()`
35-
can be called on string slices, numbers and booleans since they all implement
35+
can be called on string slices, numbers, and booleans since they all implement
3636
the `Display` trait.
3737

38-
This flavour of the extension trait pattern uses
38+
This flavor of the extension trait pattern uses
3939
[_blanket implementations_][1].
4040

4141
A blanket implementation implements a trait for all types `T` that satisfy the
@@ -45,7 +45,7 @@ assert_eq!(true.quoted(), "'true'");
4545
- Draw the students' attention to the implementation of `DisplayExt::quoted`: we
4646
can't make any assumptions about `T` other than that it implements `Display`.
4747
All our logic must either use methods from `Display` or functions/macros that
48-
don't require other traits..
48+
don't require other traits.
4949

5050
For example, we can call `format!` with `T`, but can't call `.to_uppercase()`
5151
because it is not necessarily a `String`.

src/idiomatic/leveraging-the-type-system/extension-traits/method-resolution-conflicts.md

Lines changed: 39 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,51 +9,70 @@ extension method?
99

1010
```rust,editable
1111
mod ext {
12-
pub trait StrExt {
13-
fn trim_ascii(&self) -> &str;
12+
pub trait CountOnesExt {
13+
fn count_ones(&self) -> u32;
1414
}
1515
16-
impl StrExt for String {
17-
fn trim_ascii(&self) -> &str {
18-
self.trim_start_matches(|c: char| c.is_ascii_whitespace())
16+
impl CountOnesExt for i32 {
17+
fn count_ones(&self) -> u32 {
18+
let value = *self;
19+
(0..32).filter(|i| ((value >> i) & 1i32) == 1).count() as u32
1920
}
2021
}
2122
}
2223
fn main() {
23-
pub use ext::StrExt;
24-
// Which `trim_ascii` method is invoked?
25-
// The one from `StrExt`? Or the inherent one from `str`?
26-
assert_eq!(String::from(" dad ").trim_ascii(), "dad");
24+
pub use ext::CountOnesExt;
25+
// Which `count_ones` method is invoked?
26+
// The one from `CountOnesExt`? Or the inherent one from `i32`?
27+
assert_eq!((-1i32).count_ones(), 32);
2728
}
2829
```
2930

3031
<details>
3132

32-
- The foreign type may, in a newer version, add a new inherent method with the
33+
- A foreign type may, in a newer version, add a new inherent method with the
3334
same name as our extension method.
3435

3536
Ask: What will happen in the example above? Will there be a compiler error?
3637
Will one of the two methods be given higher priority? Which one?
3738

38-
Add a `panic!("Extension trait")` in the body of `StrExt::trim_ascii` to
39-
clarify which method is being invoked.
39+
Add a `panic!("Extension trait");` in the body of `CountOnesExt::count_ones`
40+
to clarify which method is being invoked.
4041

41-
- [Inherent methods have higher priority than trait methods][1], _if_ they have
42-
the same name and the **same receiver**, e.g., they both expect `&self` as
43-
input. The situation becomes more nuanced if they use a **different
44-
receiver**, e.g., `&mut self` vs `&self`.
42+
- To prevent users of the Rust language from having to manually specify which
43+
method to use in all cases, there is a priority ordering system for how
44+
methods get "picked" first:
45+
- Immutable (`&self`) first
46+
- Inherent (method defined in the type's `impl` block) before Trait (method
47+
added by a trait impl).
48+
- Mutable (`&mut self`) Second
49+
- Inherent before Trait.
4550

46-
Change the signature of `StrExt::trim_ascii` to
47-
`fn trim_ascii(&mut self) -> &str` and modify the invocation accordingly:
51+
If every method with the same name has different mutability and was either
52+
defined in as an inherent method or trait method, with no overlap, this makes
53+
the job easy for the compiler.
54+
55+
This does introduce some ambiguity for the user, who may be confused as to why
56+
a method they're relying on is not producing expected behavior. Avoid name
57+
conflicts instead of relying on this mechanism if you can.
58+
59+
Demonstrate: Change the signature and implementation of
60+
`CountOnesExt::count_ones` to `fn count_ones(&mut self) -> u32` and modify the
61+
invocation accordingly:
4862

4963
```rust
50-
assert_eq!((&mut " dad ").trim_ascii(), "dad");
64+
assert_eq!((&mut -1i32).count_ones(), 32);
5165
```
5266

53-
Now `StrExt::trim_ascii` is invoked, rather than the inherent method, since
67+
`CountOnesExt::count_ones` is invoked, rather than the inherent method, since
5468
`&mut self` has a higher priority than `&self`, the one used by the inherent
5569
method.
5670

71+
If an immutable inherent method and a mutable trait method exist for the same
72+
type, we can specify which one to use at the call site by using
73+
`(&<value>).count_ones()` to get the immutable (higher priority) method or
74+
`(&mut <value>).count_ones()`
75+
5776
Point the students to the Rust reference for more information on
5877
[method resolution][2].
5978

src/idiomatic/leveraging-the-type-system/extension-traits/should-i-define-an-extension-trait.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ The main advantage of extension traits is **ease of discovery**.
4747
several related functions for a foreign type (e.g., `is_palindrome`,
4848
`word_count`, `to_kebab_case`), grouping them in a single `StrExt` trait is
4949
often cleaner than having multiple free functions for a user to import.
50-
- **Tradeoffs:** Despite these advantages, a bespoke extension trait might be
50+
- **Trade-offs:** Despite these advantages, a bespoke extension trait might be
5151
overkill for a single, simple function. Both approaches require an additional
5252
import, and the familiar method syntax may not justify the boilerplate of a
5353
full trait definition.

0 commit comments

Comments
 (0)