Skip to content

Commit e5da735

Browse files
authored
Idiomatic: Various tweaks and cleanup to naming conventions section (#3164)
Tweaks and feedback to the "Naming Conventions" section of Idiomatic based on my experience teaching the class, mostly focusing on making the slides more concise. Related to #3157, which also attempts to trim the section by removing some slides that I don't think are necessary. As noted in that PR, I think the section is overly long and would benefit from being a quicker tour of naming conventions, without needing to spend a lot of time on any of the slides.
1 parent 6b4b1ea commit e5da735

8 files changed

Lines changed: 51 additions & 144 deletions

File tree

src/idiomatic/foundations-api-design/predictable-api/naming-conventions/as-and-ref.md

Lines changed: 9 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -9,34 +9,21 @@ SPDX-License-Identifier: CC-BY-4.0
99

1010
# `as_` and `_ref`: reference conversions
1111

12-
`as` is a prefix for methods that convert references. `ref` is a suffix (but
13-
prefer `as`.)
14-
15-
`as` methods borrow out the primary piece of data contained in `&self`.
16-
17-
Most commonly return references, but can also return a custom borrowing type or
18-
an unsafe pointer.
19-
2012
```rust,compile_fail,editable
2113
# // Copyright 2025 Google LLC
2214
# // SPDX-License-Identifier: Apache-2.0
2315
#
2416
impl<T> Rc<T> {
25-
fn as_ptr(&self) -> *const T;
26-
2717
// Very common on container types, see how it's also on Option.
2818
fn as_ref(&self) -> &T;
19+
20+
fn as_ptr(&self) -> *const T;
2921
}
3022
3123
impl<T> Option<T> {
3224
fn as_ref(&self) -> Option<&T>;
33-
// Slices can be empty! So this is 0 or 1 elements.
34-
fn as_slice(&self) -> &[T];
35-
}
3625
37-
impl OwnedFd {
38-
// Covered later.
39-
fn as_fd(&'a self) -> BorrowedFd<'a>;
26+
fn as_slice(&self) -> &[T];
4027
}
4128
```
4229

@@ -47,46 +34,17 @@ impl OwnedFd {
4734
- The borrowing relationship is most often straightforward: the return value is
4835
a reference that borrows `self`.
4936

50-
- Borrowing can also be subtle, and merely implied.
51-
52-
- The returned value could be a custom borrowing type, fore example,
53-
`BorrowedFd` borrows `OwnedFd` through an explicit lifetime.
54-
55-
- We cover custom borrowing types later in this deep dive,
56-
[PhantomData: OwnedFd & BorrowedFd](../../../leveraging-the-type-system/borrow-checker-invariants/phantomdata-04-borrowedfd.md).
57-
58-
- The returned value could borrow `self` only logically, for example,
59-
`as_ptr()` methods return an unsafe pointer. The borrow checker does not
60-
track borrowing for pointers.
37+
- The returned value could borrow `self` only logically, for example, `as_ptr()`
38+
methods return an unsafe pointer. The borrow checker does not track borrowing
39+
for pointers.
6140

6241
- The type implementing an "as" method should contain one primary piece of data
6342
that is being borrowed out.
6443

6544
- The "as" naming convention does not work if the data type is an aggregate of
66-
many fields without an obvious primary one. Think about the call site:
67-
68-
```rust,compile_fail
69-
# // Copyright 2025 Google LLC
70-
# // SPDX-License-Identifier: Apache-2.0
71-
#
72-
my_vec.as_ptr() // OK
73-
my_person.as_first_name() // does not read right, don't use "as_"
74-
my_person.first_name() // OK
75-
```
76-
77-
- If you want to have two getters that you need to distinguish, one that
78-
returns first name by value, and another one that returns it by reference,
79-
use `_ref` suffix:
45+
many fields without an obvious primary one.
8046

81-
```rust,compile_fail
82-
# // Copyright 2025 Google LLC
83-
# // SPDX-License-Identifier: Apache-2.0
84-
#
85-
impl Person {
86-
fn first_name(&self) -> String
87-
fn first_name_ref() -> &str
88-
fn first_name_mut() -> &mut String
89-
}
90-
```
47+
- If you have two reference getters that you need to distinguish, use the
48+
`_ref` suffix.
9149

9250
</details>

src/idiomatic/foundations-api-design/predictable-api/naming-conventions/by.md

Lines changed: 12 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -16,50 +16,27 @@ Component for methods that take a custom projection or comparison function.
1616
# // SPDX-License-Identifier: Apache-2.0
1717
#
1818
impl<T> [T] {
19-
// Simplified
20-
fn sort_by(&mut self, compare: impl FnMut(&T, &T) -> Ordering);
19+
fn sort(&mut self) where T: Ord;
2120
22-
// Uses a predicate to determine what items end up in non-overlapping chunks.
23-
fn chunk_by_mut<F: FnMut(&T, &T) -> bool>(
24-
&mut self,
25-
pred: F,
26-
) -> ChunkByMut<'_, T, F>;
27-
}
21+
fn sort_by(&mut self, compare: impl FnMut(&T, &T) -> Ordering);
2822
29-
trait Iterator {
30-
// Provided method of Iterator. Simplified.
31-
fn min_by<F>(
32-
self,
33-
compare: impl FnMut(&Self::Item, &Self::Item) -> Ordering,
34-
) -> Option<Self::Item>;
23+
fn sort_by_key<K, F>(&mut self, f: F)
24+
where
25+
F: FnMut(&T) -> K,
26+
K: Ord;
3527
}
3628
```
3729

3830
<details>
39-
- Method will take a comparison or projection function.
40-
41-
A projection function here being a function that, given a reference to a value
42-
that exists in the data structure, will compute a value to perform the principle
43-
computation with.
44-
45-
Methods like `sort_by_key` allow us to sort by _the hash function I've passed to
46-
the method_ or sort by _this specific field of the data in the slice_.
47-
48-
For example, if you have a slice of values of some data structure you might want
49-
to sort them by a field of that data structure, or even a hash value of that
50-
data.
51-
52-
`sort_by` takes a comparator function directly.
5331

54-
- Most often seen in methods that sort or otherwise manipulate a slice with a
55-
custom sort or comparison function rather than by the `Ord` implementation of
56-
the type itself.
32+
- `sort_by` takes a custom comparator function that replaces the normal `Ord`
33+
comparison logic.
5734

58-
- Sometimes the "by" preposition is simply a preposition.
35+
- `sort_by_key` takes a projection function that takes the original element and
36+
returns an alternate value to use for sorting. This allow us to do things like
37+
sort by a particular field of a struct.
5938

60-
"by", like some other name components, may end up in a method name for normal
61-
linguistic reasons rather than holding specific naming convention semantic
62-
weight.
39+
- Sometimes the "by" preposition is simply a preposition:
6340

6441
- [`Read::by_ref()`](https://doc.rust-lang.org/std/io/trait.Read.html#method.by_ref)
6542

src/idiomatic/foundations-api-design/predictable-api/naming-conventions/from.md

Lines changed: 2 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,10 @@ A constructor function, strongly implying "type conversion".
1515
# // Copyright 2025 Google LLC
1616
# // SPDX-License-Identifier: Apache-2.0
1717
#
18-
impl CStr {
19-
unsafe fn from_ptr<'a>(ptr: *const i8) -> &'a CStr;
20-
}
21-
2218
impl Duration {
2319
fn from_days(days: u64) -> Duration;
2420
}
2521
26-
impl<T> Vec<T> {
27-
fn from_raw_parts(ptr: *mut T, length: usize, capacity: usize) -> Vec<T>;
28-
}
29-
3022
impl i32 {
3123
fn from_ascii(src: &[u8]) -> Result<i32, ParseIntError>;
3224
}
@@ -37,31 +29,13 @@ impl u32 {
3729
```
3830

3931
<details>
32+
4033
- Prefix for constructor-style, `From`-trait-style functions.
4134

4235
- These functions can take multiple arguments, but usually imply the user is
4336
doing more of the work than a usual constructor would.
4437

45-
`new` is still preferred for most constructor-style functions, the implication
38+
- `new` is still preferred for most constructor-style functions, the implication
4639
for `from` is transformation of one data type to another.
4740

48-
- Ask: Without looking at the standard library documentation, what would the
49-
argument type of `u32::from_be` be?
50-
51-
Answer guidance: we already see `u32::from_le_bytes` on the slide, it takes a
52-
slice of bytes. So from_le must be simpler, taking not bytes. Think about the
53-
contrast between `u32` and `be`. The argument must be a big-endian `u32`!
54-
55-
Follow-up question: How about `str::from_utf8`?
56-
57-
Answer guidance: `str` vs `utf8`. The argument can't be a `str` because every
58-
`str` is valid UTF-8. So what is the simplest way to provide UTF-8 data? A
59-
slice of bytes.
60-
61-
Follow-up: Why not `str::from_utf8_bytes`?
62-
63-
Answer: It could be in theory. However, the "omit needless words" principle
64-
applies, the word "bytes" would merely repeat the obvious - could a UTF-8
65-
sequence ever be non-bytes?
66-
6741
</details>

src/idiomatic/foundations-api-design/predictable-api/naming-conventions/into.md

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,35 +9,32 @@ SPDX-License-Identifier: CC-BY-4.0
99

1010
# `into`
1111

12-
- Prefix for methods that convert `self` into another type.
13-
14-
Consumes `self`, returns an owned value.
12+
Prefix for methods that convert `self` into another type. Consumes `self`,
13+
returns an owned value.
1514

1615
```rust,compile_fail,editable
1716
# // Copyright 2025 Google LLC
1817
# // SPDX-License-Identifier: Apache-2.0
1918
#
20-
impl<T> Vec<T> {
21-
fn into_parts(self) -> (NonNull<T>, usize, usize);
19+
pub trait IntoIterator {
20+
fn into_iter(self) -> Self::IntoIter;
2221
}
2322
24-
impl<T> Cell<T> {
25-
fn into_inner(self) -> T;
23+
impl str {
24+
fn into_string(self: Box<str>) -> String;
2625
}
2726
```
2827

2928
<details>
30-
- Prefix for a function that consumes an owned value and transforms it into a value of another type.
3129

32-
Not reinterpret cast! The data can be rearranged, reallocated, changed in any
33-
way, including losing information.
30+
- Prefix for a function that consumes an owned value and transforms it into a
31+
value of another type.
3432

35-
- corollary to `From`
33+
- Not reinterpret cast! The data can be rearranged, reallocated, changed in any
34+
way, including losing information.
3635

3736
- `into_iter` consumes a collection (like a vec, or a btreeset, or a hashmap)
3837
and produces an iterator over owned values, unlike `iter` and `iter_mut` which
3938
produce iterators over reference values.
4039

41-
- Ask the class: what will `Vec::into_raw_parts` do?
42-
4340
</details>

src/idiomatic/foundations-api-design/predictable-api/naming-conventions/is.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,11 @@ impl u32 {
2929
```
3030

3131
<details>
32-
- A boolean condition on a value.
3332

34-
- `is` prefix is preferred over methods with `not` in the name.
33+
- A boolean condition on a value.
3534

36-
There are no instances of `is_not_` in standard library methods, just use
35+
- `is` prefix is preferred over methods with `not` in the name. There are no
36+
instances of `is_not_` in standard library methods, just use
3737
`!value.is_[condition]`.
3838

3939
</details>

src/idiomatic/foundations-api-design/predictable-api/naming-conventions/mut.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,25 +16,25 @@ Suffix for access-style methods.
1616
# // SPDX-License-Identifier: Apache-2.0
1717
#
1818
impl<T> Vec<T> {
19-
// Simplified
19+
fn get(&self, index: usize) -> Option<&T>;
2020
fn get_mut(&mut self, index: usize) -> Option<&mut T>;
2121
}
2222
2323
impl<T> [T] {
24-
// Simplified
24+
fn iter(&self) -> impl Iterator<Item = &T>;
2525
fn iter_mut(&mut self) -> impl Iterator<Item = &mut T>;
2626
}
27-
28-
impl str {
29-
fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error>;
30-
}
3127
```
3228

3329
<details>
34-
- Mut for Mutability
3530

3631
- Suffix that signifies the method gives access to a mutable reference.
3732

38-
Requires mutable access to the value you're calling this method on.
33+
- Requires mutable access to the value you're calling this method on.
34+
35+
- Rust can't abstract over mutability, so there's no way to write a method that
36+
can be used both mutably and immutably. Instead, we write pairs of functions,
37+
where the immutable version gets the shorter name and the mutable version gets
38+
the `_mut` suffix.
3939

4040
</details>

src/idiomatic/foundations-api-design/predictable-api/naming-conventions/to.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,9 @@ impl u32 {
2828
```
2929

3030
<details>
31-
- Methods that create a new owned value without consuming `self`, and imply a type conversion, are named starting with `to`.
3231

33-
- This is not a borrow checker escape hatch, or an instance of unsafe code. A
34-
new value is created, the original data is left alone.
32+
- Methods that create a new owned value without consuming `self`, and imply a
33+
type conversion, are named starting with `to`.
3534

3635
- Methods that start with "to" return a different type, and strongly imply a
3736
non-trivial type conversion, or even a data transformation. For example,
@@ -42,16 +41,17 @@ impl u32 {
4241
call does not consume `self`.
4342

4443
- If you simply want to define a method that takes `&self` and returns an owned
45-
value of the same type, implement the `Clone` trait.
46-
47-
Example: to_uppercase creates a version of a string with all uppercase letters.
44+
value of the same type, implement [`Clone`] or [`ToOwned`].
4845

4946
- If you want to define a method that consumes the source value, use the "into"
5047
naming pattern.
5148

5249
- Also seen in functions that convert the endianness of primitives, or copy and
5350
expose the value of a newtype.
5451

52+
[`Clone`]: https://doc.rust-lang.org/stable/std/clone/trait.Clone.html
53+
[`ToOwned`]: https://doc.rust-lang.org/stable/std/borrow/trait.ToOwned.html
54+
5555
## More to Explore
5656

5757
- Ask the class: What's the difference between `to_owned` and `into_owned`?

src/idiomatic/foundations-api-design/predictable-api/naming-conventions/try.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ impl<T> Receiver<T> {
2727
```
2828

2929
<details>
30+
3031
- Prefix for methods that can fail, returning a `Result`.
3132

3233
- `TryFrom` is a `From`-like trait for types whose single-value constructors

0 commit comments

Comments
 (0)