diff --git a/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/as-and-ref.md b/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/as-and-ref.md index 95a929793e86..a62647631645 100644 --- a/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/as-and-ref.md +++ b/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/as-and-ref.md @@ -9,34 +9,21 @@ SPDX-License-Identifier: CC-BY-4.0 # `as_` and `_ref`: reference conversions -`as` is a prefix for methods that convert references. `ref` is a suffix (but -prefer `as`.) - -`as` methods borrow out the primary piece of data contained in `&self`. - -Most commonly return references, but can also return a custom borrowing type or -an unsafe pointer. - ```rust,compile_fail,editable # // Copyright 2025 Google LLC # // SPDX-License-Identifier: Apache-2.0 # impl Rc { - fn as_ptr(&self) -> *const T; - // Very common on container types, see how it's also on Option. fn as_ref(&self) -> &T; + + fn as_ptr(&self) -> *const T; } impl Option { fn as_ref(&self) -> Option<&T>; - // Slices can be empty! So this is 0 or 1 elements. - fn as_slice(&self) -> &[T]; -} -impl OwnedFd { - // Covered later. - fn as_fd(&'a self) -> BorrowedFd<'a>; + fn as_slice(&self) -> &[T]; } ``` @@ -47,46 +34,17 @@ impl OwnedFd { - The borrowing relationship is most often straightforward: the return value is a reference that borrows `self`. -- Borrowing can also be subtle, and merely implied. - - - The returned value could be a custom borrowing type, fore example, - `BorrowedFd` borrows `OwnedFd` through an explicit lifetime. - - - We cover custom borrowing types later in this deep dive, - [PhantomData: OwnedFd & BorrowedFd](../../../leveraging-the-type-system/borrow-checker-invariants/phantomdata-04-borrowedfd.md). - - - The returned value could borrow `self` only logically, for example, - `as_ptr()` methods return an unsafe pointer. The borrow checker does not - track borrowing for pointers. +- The returned value could borrow `self` only logically, for example, `as_ptr()` + methods return an unsafe pointer. The borrow checker does not track borrowing + for pointers. - The type implementing an "as" method should contain one primary piece of data that is being borrowed out. - The "as" naming convention does not work if the data type is an aggregate of - many fields without an obvious primary one. Think about the call site: - - ```rust,compile_fail - # // Copyright 2025 Google LLC - # // SPDX-License-Identifier: Apache-2.0 - # - my_vec.as_ptr() // OK - my_person.as_first_name() // does not read right, don't use "as_" - my_person.first_name() // OK - ``` - - - If you want to have two getters that you need to distinguish, one that - returns first name by value, and another one that returns it by reference, - use `_ref` suffix: + many fields without an obvious primary one. - ```rust,compile_fail - # // Copyright 2025 Google LLC - # // SPDX-License-Identifier: Apache-2.0 - # - impl Person { - fn first_name(&self) -> String - fn first_name_ref() -> &str - fn first_name_mut() -> &mut String - } - ``` + - If you have two reference getters that you need to distinguish, use the + `_ref` suffix. diff --git a/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/by.md b/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/by.md index c7ab6120d623..079a891dfd7f 100644 --- a/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/by.md +++ b/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/by.md @@ -16,50 +16,27 @@ Component for methods that take a custom projection or comparison function. # // SPDX-License-Identifier: Apache-2.0 # impl [T] { - // Simplified - fn sort_by(&mut self, compare: impl FnMut(&T, &T) -> Ordering); + fn sort(&mut self) where T: Ord; - // Uses a predicate to determine what items end up in non-overlapping chunks. - fn chunk_by_mut bool>( - &mut self, - pred: F, - ) -> ChunkByMut<'_, T, F>; -} + fn sort_by(&mut self, compare: impl FnMut(&T, &T) -> Ordering); -trait Iterator { - // Provided method of Iterator. Simplified. - fn min_by( - self, - compare: impl FnMut(&Self::Item, &Self::Item) -> Ordering, - ) -> Option; + fn sort_by_key(&mut self, f: F) + where + F: FnMut(&T) -> K, + K: Ord; } ```
-- Method will take a comparison or projection function. - -A projection function here being a function that, given a reference to a value -that exists in the data structure, will compute a value to perform the principle -computation with. - -Methods like `sort_by_key` allow us to sort by _the hash function I've passed to -the method_ or sort by _this specific field of the data in the slice_. - -For example, if you have a slice of values of some data structure you might want -to sort them by a field of that data structure, or even a hash value of that -data. - -`sort_by` takes a comparator function directly. -- Most often seen in methods that sort or otherwise manipulate a slice with a - custom sort or comparison function rather than by the `Ord` implementation of - the type itself. +- `sort_by` takes a custom comparator function that replaces the normal `Ord` + comparison logic. -- Sometimes the "by" preposition is simply a preposition. +- `sort_by_key` takes a projection function that takes the original element and + returns an alternate value to use for sorting. This allow us to do things like + sort by a particular field of a struct. - "by", like some other name components, may end up in a method name for normal - linguistic reasons rather than holding specific naming convention semantic - weight. +- Sometimes the "by" preposition is simply a preposition: - [`Read::by_ref()`](https://doc.rust-lang.org/std/io/trait.Read.html#method.by_ref) diff --git a/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/from.md b/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/from.md index 37292903a54e..108185d30d0c 100644 --- a/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/from.md +++ b/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/from.md @@ -15,18 +15,10 @@ A constructor function, strongly implying "type conversion". # // Copyright 2025 Google LLC # // SPDX-License-Identifier: Apache-2.0 # -impl CStr { - unsafe fn from_ptr<'a>(ptr: *const i8) -> &'a CStr; -} - impl Duration { fn from_days(days: u64) -> Duration; } -impl Vec { - fn from_raw_parts(ptr: *mut T, length: usize, capacity: usize) -> Vec; -} - impl i32 { fn from_ascii(src: &[u8]) -> Result; } @@ -37,31 +29,13 @@ impl u32 { ```
+ - Prefix for constructor-style, `From`-trait-style functions. - These functions can take multiple arguments, but usually imply the user is doing more of the work than a usual constructor would. - `new` is still preferred for most constructor-style functions, the implication +- `new` is still preferred for most constructor-style functions, the implication for `from` is transformation of one data type to another. -- Ask: Without looking at the standard library documentation, what would the - argument type of `u32::from_be` be? - - Answer guidance: we already see `u32::from_le_bytes` on the slide, it takes a - slice of bytes. So from_le must be simpler, taking not bytes. Think about the - contrast between `u32` and `be`. The argument must be a big-endian `u32`! - - Follow-up question: How about `str::from_utf8`? - - Answer guidance: `str` vs `utf8`. The argument can't be a `str` because every - `str` is valid UTF-8. So what is the simplest way to provide UTF-8 data? A - slice of bytes. - - Follow-up: Why not `str::from_utf8_bytes`? - - Answer: It could be in theory. However, the "omit needless words" principle - applies, the word "bytes" would merely repeat the obvious - could a UTF-8 - sequence ever be non-bytes? -
diff --git a/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/into.md b/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/into.md index 5b9b6c288c09..6fdae7a3cc93 100644 --- a/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/into.md +++ b/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/into.md @@ -9,35 +9,32 @@ SPDX-License-Identifier: CC-BY-4.0 # `into` -- Prefix for methods that convert `self` into another type. - -Consumes `self`, returns an owned value. +Prefix for methods that convert `self` into another type. Consumes `self`, +returns an owned value. ```rust,compile_fail,editable # // Copyright 2025 Google LLC # // SPDX-License-Identifier: Apache-2.0 # -impl Vec { - fn into_parts(self) -> (NonNull, usize, usize); +pub trait IntoIterator { + fn into_iter(self) -> Self::IntoIter; } -impl Cell { - fn into_inner(self) -> T; +impl str { + fn into_string(self: Box) -> String; } ```
-- Prefix for a function that consumes an owned value and transforms it into a value of another type. -Not reinterpret cast! The data can be rearranged, reallocated, changed in any -way, including losing information. +- Prefix for a function that consumes an owned value and transforms it into a + value of another type. -- corollary to `From` +- Not reinterpret cast! The data can be rearranged, reallocated, changed in any + way, including losing information. - `into_iter` consumes a collection (like a vec, or a btreeset, or a hashmap) and produces an iterator over owned values, unlike `iter` and `iter_mut` which produce iterators over reference values. -- Ask the class: what will `Vec::into_raw_parts` do? -
diff --git a/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/is.md b/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/is.md index bd199d7724b7..118f4c6b63e8 100644 --- a/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/is.md +++ b/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/is.md @@ -29,11 +29,11 @@ impl u32 { ```
-- A boolean condition on a value. -- `is` prefix is preferred over methods with `not` in the name. +- A boolean condition on a value. - There are no instances of `is_not_` in standard library methods, just use +- `is` prefix is preferred over methods with `not` in the name. There are no + instances of `is_not_` in standard library methods, just use `!value.is_[condition]`.
diff --git a/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/mut.md b/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/mut.md index 4a860bb2b7ae..a39c9cac2871 100644 --- a/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/mut.md +++ b/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/mut.md @@ -16,25 +16,25 @@ Suffix for access-style methods. # // SPDX-License-Identifier: Apache-2.0 # impl Vec { - // Simplified + fn get(&self, index: usize) -> Option<&T>; fn get_mut(&mut self, index: usize) -> Option<&mut T>; } impl [T] { - // Simplified + fn iter(&self) -> impl Iterator; fn iter_mut(&mut self) -> impl Iterator; } - -impl str { - fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error>; -} ```
-- Mut for Mutability - Suffix that signifies the method gives access to a mutable reference. - Requires mutable access to the value you're calling this method on. +- Requires mutable access to the value you're calling this method on. + +- Rust can't abstract over mutability, so there's no way to write a method that + can be used both mutably and immutably. Instead, we write pairs of functions, + where the immutable version gets the shorter name and the mutable version gets + the `_mut` suffix.
diff --git a/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/to.md b/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/to.md index eeebc300601f..d3f6dd39cf31 100644 --- a/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/to.md +++ b/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/to.md @@ -28,10 +28,9 @@ impl u32 { ```
-- Methods that create a new owned value without consuming `self`, and imply a type conversion, are named starting with `to`. -- This is not a borrow checker escape hatch, or an instance of unsafe code. A - new value is created, the original data is left alone. +- Methods that create a new owned value without consuming `self`, and imply a + type conversion, are named starting with `to`. - Methods that start with "to" return a different type, and strongly imply a non-trivial type conversion, or even a data transformation. For example, @@ -42,9 +41,7 @@ impl u32 { call does not consume `self`. - If you simply want to define a method that takes `&self` and returns an owned - value of the same type, implement the `Clone` trait. - -Example: to_uppercase creates a version of a string with all uppercase letters. + value of the same type, implement [`Clone`] or [`ToOwned`]. - If you want to define a method that consumes the source value, use the "into" naming pattern. @@ -52,6 +49,9 @@ Example: to_uppercase creates a version of a string with all uppercase letters. - Also seen in functions that convert the endianness of primitives, or copy and expose the value of a newtype. +[`Clone`]: https://doc.rust-lang.org/stable/std/clone/trait.Clone.html +[`ToOwned`]: https://doc.rust-lang.org/stable/std/borrow/trait.ToOwned.html + ## More to Explore - Ask the class: What's the difference between `to_owned` and `into_owned`? diff --git a/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/try.md b/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/try.md index fee589c4ec1b..1d050683b6e1 100644 --- a/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/try.md +++ b/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/try.md @@ -27,6 +27,7 @@ impl Receiver { ```
+ - Prefix for methods that can fail, returning a `Result`. - `TryFrom` is a `From`-like trait for types whose single-value constructors