Skip to content

Commit f3a7118

Browse files
Address most of the trivial feedback, run formatter
1 parent d141a8d commit f3a7118

File tree

7 files changed

+67
-38
lines changed

7 files changed

+67
-38
lines changed

src/SUMMARY.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -440,8 +440,8 @@
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-
- [Should I Define An Extension Trait?](idiomatic/leveraging-the-type-system/extension-traits/should-i-define-an-extension-trait.md)
444443
- [Extending Other Traits](idiomatic/leveraging-the-type-system/extension-traits/extending-other-traits.md)
444+
- [Should I Define An Extension Trait?](idiomatic/leveraging-the-type-system/extension-traits/should-i-define-an-extension-trait.md)
445445
- [Trait Method Conflicts](idiomatic/leveraging-the-type-system/extension-traits/trait-method-conflicts.md)
446446

447447
---

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,10 @@ pattern** to work around this limitation.
5555

5656
Rust has decided to avoid the issue altogether by forbidding the definition of
5757
new inherent methods on foreign types.
58-
59-
- Other languages (e.g, Kotlin, C#, Swift) allow adding methods to existing types, often called "extension methods." This leads to different trade-offs in terms of potential ambiguities and the need for global reasoning.
58+
59+
- Other languages (e.g, Kotlin, C#, Swift) allow adding methods to existing
60+
types, often called "extension methods." This leads to different trade-offs in
61+
terms of potential ambiguities and the need for global reasoning.
6062

6163
</details>
6264

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ assert!(!"grandma".is_palindrome());
3838
Refer to the ["Extension Trait" RFC][1] as the authoritative source for naming
3939
conventions.
4040

41-
- The extension trait implementation for a foreign type must be in the same crate as the trait itself, otherwise you'll be blocked by Rust's
41+
- The extension trait implementation for a foreign type must be in the same
42+
crate as the trait itself, otherwise you'll be blocked by Rust's
4243
[_orphan rule_][2].
4344

4445
- The extension trait must be in scope when its methods are invoked.

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

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,35 +31,41 @@ assert_eq!(true.quoted(), "'true'");
3131

3232
<details>
3333

34-
- Highlight how we added new behavior to _multiple_ types at once.
35-
`.quoted()` can be called on string slices, numbers and booleans since they
36-
all implement the `Display` trait.
34+
- 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
36+
the `Display` trait.
3737

3838
This flavour of the extension trait pattern uses
3939
[_blanket implementations_][1].
4040

41-
A blanket implementation implements a trait for all types `T`
42-
that satisfy the trait bounds specified in the `impl` block. In
43-
this case, the only requirement is that `T` implements the `Display` trait.
41+
A blanket implementation implements a trait for all types `T` that satisfy the
42+
trait bounds specified in the `impl` block. In this case, the only requirement
43+
is that `T` implements the `Display` trait.
4444

4545
- Draw the students' attention to the implementation of `DisplayExt::quoted`: we
46-
can't make any assumptions about `T` other than that it implements
47-
`Display`. All our logic must either use methods from `Display` or
48-
functions/macros that don't require other traits..
46+
can't make any assumptions about `T` other than that it implements `Display`.
47+
All our logic must either use methods from `Display` or functions/macros that
48+
don't require other traits..
49+
50+
For example, we can call `format!` with `T`, but can't call `.to_uppercase()`
51+
because it is not necessarily a `String`.
4952

50-
For example, we can call `format!` with `T`, but can't call `.to_uppercase()` because it is not necessarily a `String`.
51-
5253
We could introduce additional trait bounds on `T`, but it would restrict the
5354
set of types that can leverage the extension trait.
5455

5556
- Conventionally, the extension trait is named after the trait it extends,
5657
followed by the `Ext` suffix. In the example above, `DisplayExt`.
5758

58-
- There are entire crates that extend standard library traits with new functionality.
59+
- There are entire crates that extend standard library traits with new
60+
functionality.
61+
62+
- `itertools` crate provides the `Itertools` trait that extends `Iterator`. It
63+
adds many iterator adapters, such as `interleave` and `unique`. It provides
64+
new algorithmic building blocks for iterator pipelines built with method
65+
chaining.
5966

60-
- `itertools` crate provides the `Itertools` trait that extends `Iterator`. It adds many iterator adapters, such as `interleave` and `unique`. It provides new algorithmic building blocks for iterator pipelines built with method chaining.
61-
62-
- `futures` crate provides the `FutureExt` trait, which extends the `Future` trait with new combinators and helper methods.
67+
- `futures` crate provides the `FutureExt` trait, which extends the `Future`
68+
trait with new combinators and helper methods.
6369

6470
## More To Explore
6571

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

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,41 +7,41 @@ minutes: 15
77
What happens when you have a name conflict between an inherent method and an
88
extension method?
99

10-
```rust
10+
```rust,editable
1111
mod ext {
1212
pub trait StrExt {
1313
fn trim_ascii(&self) -> &str;
1414
}
1515
16-
impl StrExt for &str {
16+
impl StrExt for String {
1717
fn trim_ascii(&self) -> &str {
1818
self.trim_start_matches(|c: char| c.is_ascii_whitespace())
1919
}
2020
}
2121
}
22-
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!(" dad ".trim_ascii(), "dad");
22+
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");
27+
}
2728
```
2829

2930
<details>
3031

3132
- The foreign type may, in a newer version, add a new inherent method with the
3233
same name as our extension method.
3334

34-
Survey the class: what do the students think will happen in the example above?
35-
Will there be a compiler error? Will one of the two methods be given higher
36-
priority? Which one?
35+
Ask: What will happen in the example above? Will there be a compiler error?
36+
Will one of the two methods be given higher priority? Which one?
3737

3838
Add a `panic!("Extension trait")` in the body of `StrExt::trim_ascii` to
3939
clarify which method is being invoked.
4040

4141
- [Inherent methods have higher priority than trait methods][1], _if_ they have
4242
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 receiver**,
44-
e.g., `&mut self` vs `&self`.
43+
input. The situation becomes more nuanced if they use a **different
44+
receiver**, e.g., `&mut self` vs `&self`.
4545

4646
Change the signature of `StrExt::trim_ascii` to
4747
`fn trim_ascii(&mut self) -> &str` and modify the invocation accordingly:

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

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,28 @@ The main advantage of extension traits is **ease of discovery**.
2828

2929
<details>
3030

31-
- Extension methods can be easier to discover than free functions. Language servers (e.g., `rust-analyzer`) will suggest them if you type `.` after an instance of the foreign type.
32-
33-
- However, a bespoke extension trait might be overkill for a single method. Both approaches require an additional import, and the familiar method syntax may not justify the boilerplate of a full trait definition.
31+
- Extension methods can be easier to discover than free functions. Language
32+
servers (e.g., `rust-analyzer`) will suggest them if you type `.` after an
33+
instance of the foreign type.
34+
35+
- However, a bespoke extension trait might be overkill for a single method. Both
36+
approaches require an additional import, and the familiar method syntax may
37+
not justify the boilerplate of a full trait definition.
38+
39+
- **Discoverability:** Extension methods are easier to discover than free
40+
functions. Language servers (e.g., `rust-analyzer`) will suggest them if you
41+
type `.` after an instance of the foreign type.
42+
- **Method Chaining:** A major ergonomic win for extension traits is method
43+
chaining. This is the foundation of the `Iterator` trait, allowing for fluent
44+
calls like `data.iter().filter(...).map(...)`. Achieving this with free
45+
functions would be far more cumbersome (`map(filter(iter(data), ...), ...)`).
46+
- **API Cohesion:** Extension traits help create a cohesive API. If you have
47+
several related functions for a foreign type (e.g., `is_palindrome`,
48+
`word_count`, `to_kebab_case`), grouping them in a single `StrExt` trait is
49+
often cleaner than having multiple free functions for a user to import.
50+
- **Tradeoffs:** Despite these advantages, a bespoke extension trait might be
51+
overkill for a single, simple function. Both approaches require an additional
52+
import, and the familiar method syntax may not justify the boilerplate of a
53+
full trait definition.
3454

3555
</details>

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,16 +45,16 @@ assert!("dad".is_palindrome());
4545
the same type may define a method with a name that conflicts with your own
4646
extension method.
4747

48-
Survey the class: what do the students think will happen in the example above?
49-
Will there be a compiler error? Will one of the two methods be given higher
50-
priority? Which one?
48+
Ask: what will happen in the example above? Will there be a compiler error?
49+
Will one of the two methods be given higher priority? Which one?
5150

5251
- The compiler rejects the code because it cannot determine which method to
5352
invoke. Neither `Ext1` nor `Ext2` has a higher priority than the other.
5453

5554
To resolve this conflict, you must specify which trait you want to use. For
5655
example, you can call `Ext1::is_palindrome("dad")` or
57-
`Ext2::is_palindrome("dad")`. Demonstrate this syntax and that the updated code compiles.
56+
`Ext2::is_palindrome("dad")`. Demonstrate this syntax and that the updated
57+
code compiles.
5858

5959
For methods with more complex signatures, you may need to use a more explicit
6060
[fully-qualified syntax][1].

0 commit comments

Comments
 (0)