From 9c1d7d1f292ec1d20aa493b7b7fd07dcc7261017 Mon Sep 17 00:00:00 2001 From: tall-vase Date: Fri, 5 Dec 2025 13:25:31 +0000 Subject: [PATCH] Bring in existing foundations of API design work from google doc --- src/SUMMARY.md | 33 +++++++++ src/idiomatic/foundations-api-design.md | 3 + .../clarity-readability.md | 0 .../meaningful-doc-comments.md | 23 ++++++ .../avoid-redundancy.md | 55 ++++++++++++++ .../name-drop-signpost.md | 55 ++++++++++++++ .../meaningful-doc-comments/what-isnt-docs.md | 22 ++++++ .../what-why-not-how-where.md | 46 ++++++++++++ .../who-are-you-writing-for.md | 34 +++++++++ .../foundations-api-design/predictable-api.md | 10 +++ .../predictable-api/common-traits.md | 30 ++++++++ .../predictable-api/common-traits/01-debug.md | 74 +++++++++++++++++++ .../common-traits/02-partialeq-eq.md | 53 +++++++++++++ .../common-traits/03-partialord-ord.md | 64 ++++++++++++++++ .../predictable-api/common-traits/04-hash.md | 36 +++++++++ .../predictable-api/common-traits/05-clone.md | 48 ++++++++++++ .../predictable-api/common-traits/06-copy.md | 47 ++++++++++++ .../predictable-api/common-traits/07-serde.md | 36 +++++++++ .../common-traits/08-from-into.md | 58 +++++++++++++++ .../common-traits/09-try-from-into.md | 45 +++++++++++ .../common-traits/10-display.md | 46 ++++++++++++ .../predictable-api/naming-conventions.md | 20 +++++ .../naming-conventions/01-get.md | 31 ++++++++ .../naming-conventions/02-push.md | 29 ++++++++ .../naming-conventions/03-is.md | 27 +++++++ .../naming-conventions/04-mut.md | 24 ++++++ .../naming-conventions/05-try.md | 27 +++++++ .../naming-conventions/06-with.md | 31 ++++++++ .../naming-conventions/07-from.md | 25 +++++++ .../naming-conventions/08-into.md | 29 ++++++++ .../naming-conventions/09-owned.md | 21 ++++++ .../naming-conventions/10-by.md | 25 +++++++ .../naming-conventions/11-unchecked.md | 25 +++++++ .../naming-conventions/12-to.md | 29 ++++++++ .../naming-conventions/13-as-and-ref.md | 38 ++++++++++ .../naming-conventions/14-mini-exercise.md | 32 ++++++++ 36 files changed, 1231 insertions(+) create mode 100644 src/idiomatic/foundations-api-design.md create mode 100644 src/idiomatic/foundations-api-design/clarity-readability.md create mode 100644 src/idiomatic/foundations-api-design/meaningful-doc-comments.md create mode 100644 src/idiomatic/foundations-api-design/meaningful-doc-comments/avoid-redundancy.md create mode 100644 src/idiomatic/foundations-api-design/meaningful-doc-comments/name-drop-signpost.md create mode 100644 src/idiomatic/foundations-api-design/meaningful-doc-comments/what-isnt-docs.md create mode 100644 src/idiomatic/foundations-api-design/meaningful-doc-comments/what-why-not-how-where.md create mode 100644 src/idiomatic/foundations-api-design/meaningful-doc-comments/who-are-you-writing-for.md create mode 100644 src/idiomatic/foundations-api-design/predictable-api.md create mode 100644 src/idiomatic/foundations-api-design/predictable-api/common-traits.md create mode 100644 src/idiomatic/foundations-api-design/predictable-api/common-traits/01-debug.md create mode 100644 src/idiomatic/foundations-api-design/predictable-api/common-traits/02-partialeq-eq.md create mode 100644 src/idiomatic/foundations-api-design/predictable-api/common-traits/03-partialord-ord.md create mode 100644 src/idiomatic/foundations-api-design/predictable-api/common-traits/04-hash.md create mode 100644 src/idiomatic/foundations-api-design/predictable-api/common-traits/05-clone.md create mode 100644 src/idiomatic/foundations-api-design/predictable-api/common-traits/06-copy.md create mode 100644 src/idiomatic/foundations-api-design/predictable-api/common-traits/07-serde.md create mode 100644 src/idiomatic/foundations-api-design/predictable-api/common-traits/08-from-into.md create mode 100644 src/idiomatic/foundations-api-design/predictable-api/common-traits/09-try-from-into.md create mode 100644 src/idiomatic/foundations-api-design/predictable-api/common-traits/10-display.md create mode 100644 src/idiomatic/foundations-api-design/predictable-api/naming-conventions.md create mode 100644 src/idiomatic/foundations-api-design/predictable-api/naming-conventions/01-get.md create mode 100644 src/idiomatic/foundations-api-design/predictable-api/naming-conventions/02-push.md create mode 100644 src/idiomatic/foundations-api-design/predictable-api/naming-conventions/03-is.md create mode 100644 src/idiomatic/foundations-api-design/predictable-api/naming-conventions/04-mut.md create mode 100644 src/idiomatic/foundations-api-design/predictable-api/naming-conventions/05-try.md create mode 100644 src/idiomatic/foundations-api-design/predictable-api/naming-conventions/06-with.md create mode 100644 src/idiomatic/foundations-api-design/predictable-api/naming-conventions/07-from.md create mode 100644 src/idiomatic/foundations-api-design/predictable-api/naming-conventions/08-into.md create mode 100644 src/idiomatic/foundations-api-design/predictable-api/naming-conventions/09-owned.md create mode 100644 src/idiomatic/foundations-api-design/predictable-api/naming-conventions/10-by.md create mode 100644 src/idiomatic/foundations-api-design/predictable-api/naming-conventions/11-unchecked.md create mode 100644 src/idiomatic/foundations-api-design/predictable-api/naming-conventions/12-to.md create mode 100644 src/idiomatic/foundations-api-design/predictable-api/naming-conventions/13-as-and-ref.md create mode 100644 src/idiomatic/foundations-api-design/predictable-api/naming-conventions/14-mini-exercise.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index a5929bad8455..d9f89f076291 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -436,6 +436,39 @@ # Idiomatic Rust - [Welcome](idiomatic/welcome.md) +- [Foundations of API Design](idiomatic/foundations-api-design.md) + - [Meaningful Doc Comments](idiomatic/foundations-api-design/meaningful-doc-comments.md) + - [Avoid Redundancy](idiomatic/foundations-api-design/meaningful-doc-comments/avoid-redundancy.md) + - [Name Drop and Signpost](idiomatic/foundations-api-design/meaningful-doc-comments/name-drop-signpost.md) + - [Name and Signature are Not Enough](idiomatic/foundations-api-design/meaningful-doc-comments/what-isnt-docs.md) + - [What and Why, not How and Where](idiomatic/foundations-api-design/meaningful-doc-comments/what-why-not-how-where.md) + - [Who Are You Writing For?](idiomatic/foundations-api-design/meaningful-doc-comments/who-are-you-writing-for.md) + - [Predictable API](idiomatic/foundations-api-design/predictable-api.md) + - [Naming conventions](idiomatic/foundations-api-design/predictable-api/naming-conventions.md) + - [Get](idiomatic/foundations-api-design/predictable-api/naming-conventions/01-get.md) + - [Push](idiomatic/foundations-api-design/predictable-api/naming-conventions/02-push.md) + - [Is](idiomatic/foundations-api-design/predictable-api/naming-conventions/03-is.md) + - [Mut](idiomatic/foundations-api-design/predictable-api/naming-conventions/04-mut.md) + - [Try](idiomatic/foundations-api-design/predictable-api/naming-conventions/05-try.md) + - [With](idiomatic/foundations-api-design/predictable-api/naming-conventions/06-with.md) + - [From](idiomatic/foundations-api-design/predictable-api/naming-conventions/07-from.md) + - [Into](idiomatic/foundations-api-design/predictable-api/naming-conventions/08-into.md) + - [Owned](idiomatic/foundations-api-design/predictable-api/naming-conventions/09-owned.md) + - [By](idiomatic/foundations-api-design/predictable-api/naming-conventions/10-by.md) + - [To](idiomatic/foundations-api-design/predictable-api/naming-conventions/12-to.md) + - [As and Ref](idiomatic/foundations-api-design/predictable-api/naming-conventions/13-as-and-ref.md) + - [Mini Exercise](idiomatic/foundations-api-design/predictable-api/naming-conventions/14-mini-exercise.md) + - [Implementing Common Traits](idiomatic/foundations-api-design/predictable-api/common-traits.md) + - [Debug](idiomatic/foundations-api-design/predictable-api/common-traits/01-debug.md) + - [PartialEq and Eq](idiomatic/foundations-api-design/predictable-api/common-traits/02-partialeq-eq.md) + - [PartialOrd and Ord](idiomatic/foundations-api-design/predictable-api/common-traits/03-partialord-ord.md) + - [Hash](idiomatic/foundations-api-design/predictable-api/common-traits/04-hash.md) + - [Clone](idiomatic/foundations-api-design/predictable-api/common-traits/05-clone.md) + - [Copy](idiomatic/foundations-api-design/predictable-api/common-traits/06-copy.md) + - [Serialize and Deserialize](idiomatic/foundations-api-design/predictable-api/common-traits/07-serde.md) + - [From and Into](idiomatic/foundations-api-design/predictable-api/common-traits/08-from-into.md) + - [TryFrom and TryInto](idiomatic/foundations-api-design/predictable-api/common-traits/09-try-from-into.md) + - [Display](idiomatic/foundations-api-design/predictable-api/common-traits/10-display.md) - [Leveraging the Type System](idiomatic/leveraging-the-type-system.md) - [Newtype Pattern](idiomatic/leveraging-the-type-system/newtype-pattern.md) - [Semantic Confusion](idiomatic/leveraging-the-type-system/newtype-pattern/semantic-confusion.md) diff --git a/src/idiomatic/foundations-api-design.md b/src/idiomatic/foundations-api-design.md new file mode 100644 index 000000000000..ab32b5a95bae --- /dev/null +++ b/src/idiomatic/foundations-api-design.md @@ -0,0 +1,3 @@ +--- +minutes: 2 +--- diff --git a/src/idiomatic/foundations-api-design/clarity-readability.md b/src/idiomatic/foundations-api-design/clarity-readability.md new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/src/idiomatic/foundations-api-design/meaningful-doc-comments.md b/src/idiomatic/foundations-api-design/meaningful-doc-comments.md new file mode 100644 index 000000000000..de7fb8c72eec --- /dev/null +++ b/src/idiomatic/foundations-api-design/meaningful-doc-comments.md @@ -0,0 +1,23 @@ +--- +minutes: 5 +--- + +# Meaningful Doc Comments + +```rust,compile_fail +/// API for Domain // ❌ +pub mod domain {} + +/// Function from A to B // ❌ +fn a_to_b(a: A) -> B {...} + +/// Does X // ❌ +fn do_x() {} +``` + +Doc comments are the most common source of documentation most developers will +engage with. + +It's important to write doc comments that developers will appreciate reading, +that gives them the information they are looking for and doesn't just re-state +the obvious. diff --git a/src/idiomatic/foundations-api-design/meaningful-doc-comments/avoid-redundancy.md b/src/idiomatic/foundations-api-design/meaningful-doc-comments/avoid-redundancy.md new file mode 100644 index 000000000000..9127495e9709 --- /dev/null +++ b/src/idiomatic/foundations-api-design/meaningful-doc-comments/avoid-redundancy.md @@ -0,0 +1,55 @@ +--- +minutes: 15 +--- + +# Avoiding Redundancy + +Function names and type signatures already document some information, avoid +repeating them! + +```rust +// Don't do this! +/// Parses an ipv4 from a str. Returns an option for failure modes. +fn parse_ip_addr_v4(input: &str) -> Option { ... } + +// TODO: couple more of these, for the instructor to go through with students. +``` + +
+- Motivation: Documentation that repeats name/signature information provides nothing new to the API user. + +- This is an understandable pattern to fall into! + + Naive approach to "always document your code," follows this advice literally + but does not follow the intent. + + Tests might enforce documentation coverage, this kind of documentation is an + easy fix. + +- The name of a function or type is part of the documentation of that function + or type. + + Similarly, the signature of a function is part of the documentation of that + function. + + Therefore: aspects of the subject are already covered when you start writing + doc comments! + +- Many areas of the standard library have minimal documentation because the name + and types do give enough information. + + Rule of Thumb: What information is missing from a user's perspective? Other + than name, signature, and irrelevant details of the implementation. + +- Don't drop down to language basics! Assume the reader of doc comments has an + intermediate understanding of the language itself, it's the API you're working + on that you're trying to document. + +- If there is a complex topic involved with the functions and types you're + documenting, signpost to a "source of truth" if one exists such as a blog + post, an internal document, a paper etc. + +- Collaborate with Students: Go through the methods in the slide and discuss + what might be relevant to an API user. + +
diff --git a/src/idiomatic/foundations-api-design/meaningful-doc-comments/name-drop-signpost.md b/src/idiomatic/foundations-api-design/meaningful-doc-comments/name-drop-signpost.md new file mode 100644 index 000000000000..be513a295f88 --- /dev/null +++ b/src/idiomatic/foundations-api-design/meaningful-doc-comments/name-drop-signpost.md @@ -0,0 +1,55 @@ +--- +minutes: 15 +--- + +# Name-dropping keywords and signposting topics + +```rust +/// This function covers , for further reading see: reference A, B, C. +fn highly_specific_function(/* */) { /* ... */ +} +``` + +
+- Motivation: Readers of documentation will not be closely reading most of your doc comments like they would dialogue in a novel they love. + +Users will most likely be skimming and scan-reading to find the part of the +documentation that is relevant to whatever problem they're trying to solve in +the moment. + +Once a user has found a keyword or potential signpost that's relevant to them +they will begin to search for context surrounding what is being documented. + +- Ask the class: What do you look for in documentation? Focus on the + moment-to-moment searching for information here, not general values in + documentation + +- Name-drop keywords close to the beginning of a paragraph. + + This aids skimming and scanning, as the first few words of a paragraph stand + out the most. + + Skimming and scanning lets users quickly navigate a text, keeping keywords as + close to the beginning of a paragraph as possible lets a user + +- Signpost, but don't over-explain. + + Users will not necessarily have the same domain expertise as an API designer. + + If a tangential, specialist term or acronym is mentioned try to bring in + enough context such that a novice could quickly do more research. + +- Signposting often happens organically, consider a networking library that + mentions various protocols. But when it doesn't happen organically, it can be + difficult to choose what to mention. + + Rule of thumb: API developers should be asking themselves "if a novice ran + into what they are documenting, what sources would they look up and are there + any red herrings they might end up following"? + + Users should be given enough information to look up subjects on their own. + +- What we've already covered, predictability of an API including the naming + conventions, is a form of signposting. + +
diff --git a/src/idiomatic/foundations-api-design/meaningful-doc-comments/what-isnt-docs.md b/src/idiomatic/foundations-api-design/meaningful-doc-comments/what-isnt-docs.md new file mode 100644 index 000000000000..e67b4d453485 --- /dev/null +++ b/src/idiomatic/foundations-api-design/meaningful-doc-comments/what-isnt-docs.md @@ -0,0 +1,22 @@ +--- +minutes: 5 +--- + +Names and Signatures are not full documentation + +```rust +``` + +
+- Motivation: API designers can over-commit to the idea that a function name and signature is enough documentation. + +It's better than nothing, but it's worse than good documentation. + +- Again, names and types are _part_ of the documentation. They are not always + the full story! + +- TODO: give some rules of thumb for when to go into more detail, + cross-reference rust stdlib docs. This may live better in the name conventions + area. + +
diff --git a/src/idiomatic/foundations-api-design/meaningful-doc-comments/what-why-not-how-where.md b/src/idiomatic/foundations-api-design/meaningful-doc-comments/what-why-not-how-where.md new file mode 100644 index 000000000000..9eeb41f7f7d1 --- /dev/null +++ b/src/idiomatic/foundations-api-design/meaningful-doc-comments/what-why-not-how-where.md @@ -0,0 +1,46 @@ +--- +minutes: 10 +--- + +# Why and What, not How and Where + +Avoid documenting irrelevant details that may frequently change. + +```rust,no_compile +/// Sorts a slice. Implemented using recursive quicksort. +fn sort_quickly(to_sort: &mut [T]) { /* ... */ +} + +/// Calls an org-internal service using reqwest. +fn ask_service(url: &str) -> String { /* ... */ +} +``` + +
+- Motivation: Using doc comments to explain how a function does something internally means if that internal implementation detail changes, the doc comment needs to change as well. + +Internal information is likely irrelevant to a user. Imagine explaining in a doc +comment for a function that you're using for loops to solve a problem, what is +the point of this information? + +- It could be that the implementation is necessary to explain, but this is + likely due to whatever effects or invariants the user of that API needs to be + aware of instead. + + Focus on those effects and invariants instead of instead of the implementation + details themselves. + + Reiterate: Implementation details can and will change, so do not explain these + details. + + TODO: Real-life example of something appropriate to a large system. + +- Don't talk about where something is used for the sake of it. + + This is another instance where this information can become stale quickly. + +- Prefer instead to focus on what the function does (though again, not how it is + implemented) for a user trying to reach this practical information as quickly + as possible. + +
diff --git a/src/idiomatic/foundations-api-design/meaningful-doc-comments/who-are-you-writing-for.md b/src/idiomatic/foundations-api-design/meaningful-doc-comments/who-are-you-writing-for.md new file mode 100644 index 000000000000..6f7545283c3e --- /dev/null +++ b/src/idiomatic/foundations-api-design/meaningful-doc-comments/who-are-you-writing-for.md @@ -0,0 +1,34 @@ +--- +minutes: 10 +--- + +# Who are you writing for? + +Colleagues, collaborators, largely-silent API users, or just yourself? + +```rust +// TODO: What's a good illustration here? +``` + +
+- Motivation: It can be easy to fall into a pattern of writing only for you, but most documentation is for people coming in with a different perspective. + +- Unintentionally writing for yourself can lead to people not understanding a + point you're trying to make or the concept you're trying to articulate. + +- Imagine a version of you, or others you've known, struggling to find practical + information while going through documentation. + + Keep this idea of a person in mind when thinking about what areas of a + codebase need attention for doc comments. + +- Who are you writing for? + +- Also imagine a version of you, or others you've known, who is struggling to + find the important details in winding, extensive doc comments. Don't give too + much information. +- Always ask: Is this documentation making it difficult for the API user? Are + they able to quickly grasp what they need or find out where they could need + it? + +
diff --git a/src/idiomatic/foundations-api-design/predictable-api.md b/src/idiomatic/foundations-api-design/predictable-api.md new file mode 100644 index 000000000000..a1dc020edd8a --- /dev/null +++ b/src/idiomatic/foundations-api-design/predictable-api.md @@ -0,0 +1,10 @@ +--- +minutes: 2 +--- + +# Predictable API + +Keep your APIs predictable through naming conventions and implementing common +traits. + + diff --git a/src/idiomatic/foundations-api-design/predictable-api/common-traits.md b/src/idiomatic/foundations-api-design/predictable-api/common-traits.md new file mode 100644 index 000000000000..9c25c382f465 --- /dev/null +++ b/src/idiomatic/foundations-api-design/predictable-api/common-traits.md @@ -0,0 +1,30 @@ +--- +minutes: 5 +--- + +# Common Traits to Implement + +```rust +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone /* ... */)] +pub struct MyData { + pub name: String, + pub number: usize, + pub data: [u8; 64], +} +``` + +
+- Traits are one of the most potent tools in the Rust language. The language and ecosystem expects you to use them, and so a big part of _predictability_ is what traits are implemented for a type! + +- Traits should be liberally implemented on types you author, but there are + caveats! + +- Remember, many traits have the ability to be _derived_: to have a compiler + plugin (macro) write the implementation for you! + +- Authors of ecosystem traits (like De/Serialize) have made derive + implementations for traits available to users, leading to very little + commitment needed on the developer side for implementing these kinds of + traits! + +
diff --git a/src/idiomatic/foundations-api-design/predictable-api/common-traits/01-debug.md b/src/idiomatic/foundations-api-design/predictable-api/common-traits/01-debug.md new file mode 100644 index 000000000000..83dbca2482df --- /dev/null +++ b/src/idiomatic/foundations-api-design/predictable-api/common-traits/01-debug.md @@ -0,0 +1,74 @@ +--- +minutes: 5 +--- + +# Debug + +"Write to string" trait, for debug purposes. + +Derivable: ✅ When to implement: Almost always + +```rust +// pub trait Debug { +// fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>; +// } + +#[derive(Debug)] +pub struct Date { + day: u8, + month: u8, + year: i64, +} + +#[derive(Debug)] +pub struct User { + name: String, + date_of_birth: Date, +} + +pub struct PlainTextPassword { + password: String, + hint: String, +} + +impl std::fmt::Debug for PlainTextPassword { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("PlainTextPassword") + .field("hint", &self.hint) + .field("password", &"[omitted]") + .finish() + } +} + +fn main() { + let user = User { + name: "Alice".to_string(), + date_of_birth: Date { day: 31, month: 10, year: 2002 }, + }; + + println!("{user:?}"); + println!( + "{:?}", + PlainTextPassword { + password: "Password123".to_string(), + hint: "Used it for years".to_string() + } + ); +} +``` + +
+- Provides trivial "write to string" functionality. + +- Formatting for _debug information_ for programmers during , not appearance or + serialization. + +- Allows for use of `{:?}` and `{#?}` interpolation in string formatting macros. + +- When to not derive/implement: If a struct holds sensitive data, investigate if + you should implement Debug for it. + + If Debug is needed, consider manually implementing Debug rather than deriving + it. Omit the sensitive data from the implementation. + +
diff --git a/src/idiomatic/foundations-api-design/predictable-api/common-traits/02-partialeq-eq.md b/src/idiomatic/foundations-api-design/predictable-api/common-traits/02-partialeq-eq.md new file mode 100644 index 000000000000..1336c8453c96 --- /dev/null +++ b/src/idiomatic/foundations-api-design/predictable-api/common-traits/02-partialeq-eq.md @@ -0,0 +1,53 @@ +--- +minutes: 10 +--- + +PartialEq and Eq + +Partial equality & Total equality. + +Derivable: ✅ When to implement: Almost always. + +```rust +// pub trait PartialEq +//{ +// // Required method +// fn eq(&self, other: &Rhs) -> bool; +// +// // Provided method +// fn ne(&self, other: &Rhs) -> bool { ... } +// } +// +// pub trait Eq: PartialEq { } + +#[derive(PartialEq, Eq)] +pub struct User { name: String, favorite_number: i32 } + +let alice = User { name: "alice".to_string(), favorite_number: 1_000_042 }; +let bob = User { name: "bob".to_string(), favorite_number: 42 }; + +dbg!(alice == alice); +dbg!(alice == bob); +``` + +
+- Equality-related methods. If a type implements `PartialEq`/`Eq` then you can use the `==` operator with that type. + +- A type can't implement `Eq` without implementing `PartialEq`. + +- Reminder: Partial means "there are invalid members of this set for this + function." + + This doesn't mean that equality will panic, or that it returns a result, just + that there may be values that may not behave as you expect equality to behave. + + For example, with floating point values `NaN` is an outlier: `NaN == NaN` is + false, despite bitwise equality. + + `PartialEq` exists to separate types like f32/f64 from types with Total + Equality. + +- You can implement `PartialEq` between different types, but this is mostly + useful for reference/smart pointer types. + +
diff --git a/src/idiomatic/foundations-api-design/predictable-api/common-traits/03-partialord-ord.md b/src/idiomatic/foundations-api-design/predictable-api/common-traits/03-partialord-ord.md new file mode 100644 index 000000000000..b55f856738f8 --- /dev/null +++ b/src/idiomatic/foundations-api-design/predictable-api/common-traits/03-partialord-ord.md @@ -0,0 +1,64 @@ +--- +minutes: 10 +--- + +# PartialOrd and Ord + +Partial ordering & Total ordering. + +Derivable: ✅ When to implement: Almost always. + +```rust +// pub trait PartialOrd: PartialEq +// { +// // Required method +// fn partial_cmp(&self, other: &Rhs) -> Option; +// +// /* Provided methods omitted */ +// } +// pub trait Ord: Eq + PartialOrd { +// // Required method +// fn cmp(&self, other: &Self) -> Ordering; +// +// /* Provided methods omitted */ +// } + +#[derive(PartialEq, PartialOrd)] +pub struct Partially(f32); + +#[derive(PartialEq, Eq, PartialOrd, Ord)] +pub struct Totally { + id: u32, + name: String, +} +``` + +
+- Comparison-related methods. If a type implements `PartialOrd`/`Ord` then you can use comparison operators (`<`, `<=`, `>`, `>=`) with that type. + +`Ord` gives access to `min`, `max`, and `clamp` methods. + +- When derived, compares things in the order they are defined. + + For enums this means each variant is considered "greater than" the last as + they are written. + + For structs this means fields are compared as they are written, so `id` fields + are compared before `name` fields in `Totally`. + +- Prerequisites: `PartialEq` for `PartialOrd`, `Eq` for `Ord`. + + To implement `Ord`, a type must also implement `PartialEq`, `Eq`, and + `PartialOrd`. + +- Like with `PartialEq` and `Eq`, a type cannot implement `Ord` without + implementing `PartialOrd`. + + Like those equality traits, `PartialOrd` exists to separate types with + non-total ordering (particularly floating-point numbers) from types with total + ordering. + +- Used for sorting/searching algorithms and maintaining the ordering of + `BTreeMap`/`BTreeSet` style data types. + +
diff --git a/src/idiomatic/foundations-api-design/predictable-api/common-traits/04-hash.md b/src/idiomatic/foundations-api-design/predictable-api/common-traits/04-hash.md new file mode 100644 index 000000000000..eff5d40c3432 --- /dev/null +++ b/src/idiomatic/foundations-api-design/predictable-api/common-traits/04-hash.md @@ -0,0 +1,36 @@ +--- +minutes: 2 +--- + +# Hash + +Performing a hash on a type. + +Derivable: ✅ When to implement: Almost always. + +```rust +// pub trait Hash { +// // Required method +// fn hash(&self, state: &mut H) +// where H: Hasher; +// +// // Provided method +// fn hash_slice(data: &[Self], state: &mut H) +// where H: Hasher, +// Self: Sized { ... } +// } + +#[derive(Hash)] +pub struct User { + id: u32, + name: String, + friends: Vec, +} +``` + +
+- Allows a type to be used in hash algorithms. + +- Most commonly used with data structures like `HashMap`. + +
diff --git a/src/idiomatic/foundations-api-design/predictable-api/common-traits/05-clone.md b/src/idiomatic/foundations-api-design/predictable-api/common-traits/05-clone.md new file mode 100644 index 000000000000..67070b21dd7c --- /dev/null +++ b/src/idiomatic/foundations-api-design/predictable-api/common-traits/05-clone.md @@ -0,0 +1,48 @@ +--- +minutes: 5 +--- + +# Clone + +Deep-copy a type or duplicate a smart, shareable pointer. + +Derivable: ✅ When to implement: If duplicating doesn't break invariants. + +```rust +// pub trait Clone: Sized { +// // Required method +// fn clone(&self) -> Self; +// +// // Provided methods omitted +// } + +use std::collections::BTreeMap; +use std::rc::Rc; + +#[derive(Clone)] +pub struct LotsOfData { + string: String, + vec: Vec, + set: BTreeSet, +} + +let lots_of_data = LotsOfData { + string: "String".to_string(), + vec: vec![1; 255], + set: [1, 2, 3, 4, 5, 6, 7, 8].iter().collect(), +} + +let lod_cloned = lots_of_data.clone(); + +let reference_counted = Rc::new(lots_of_data); +// Copies the reference-counted pointer, not the value. +let reference_copied = reference_counted.clone(); +``` + +
+- Deep clones a value, or in the case of smart pointers like `Rc`/`Arc` create a new instance of that pointer. + +- When to not implement/derive: For types that, to maintain an invariant, the + value should not be duplicated. We'll touch on this later in Idiomatic Rust. + +
diff --git a/src/idiomatic/foundations-api-design/predictable-api/common-traits/06-copy.md b/src/idiomatic/foundations-api-design/predictable-api/common-traits/06-copy.md new file mode 100644 index 000000000000..aed0f11ddbc7 --- /dev/null +++ b/src/idiomatic/foundations-api-design/predictable-api/common-traits/06-copy.md @@ -0,0 +1,47 @@ +--- +minutes: 10 +--- + +# Copy + +Like `Clone`, but indicates the type is can be bitwise copied. + +Derivable: ✅ When to implement: Sometimes. + +```rust +// Copy is just a marker trait with Clone as a supertrait. +// pub trait Copy: Clone { } + +#[derive(Clone, Copy)] +pub struct Copyable(u8, u16, u32, u64); +``` + +
+- Clone represents a deep clone, and so does copy, but copy suggests to the compiler that a value can be copied bitwise. + +- When not to implement/derive: If you do not want to implicitly create copies + when dereferencing values of a type, do not implement this trait. + + Copy enables implicit duplication, so be careful about what types you're + implementing this on. + +- Ask the class: Can a type with heap data (`Vec`, `BTreeMap`, `Rc`, etc.) be + copy? Should it be? + + It both cannot and should not, this is a misuse of this trait. + + Bitwise copying on these types would mean types with heap data would no longer + have exclusive ownership of a pointer, breaking the invariants usually upheld + by Rust and its ecosystem. + + Multiple `Vec`s would point to the same data in memory. Adding and removing + data would only update individual `Vec`s length and capacity values. The same + for `BTreeMap`. + + Bitwise copying of `Rc`s would not update the reference counting value within + the pointers, meaning there could be two instances of a `Rc` value that + believe themselves to be the only `Rc` for that pointer. Once one of them is + destroyed, the reference count will become 0 on one of them and the inner + value dropped despite there being another `Rc` still alive. + +
diff --git a/src/idiomatic/foundations-api-design/predictable-api/common-traits/07-serde.md b/src/idiomatic/foundations-api-design/predictable-api/common-traits/07-serde.md new file mode 100644 index 000000000000..c36ec9282375 --- /dev/null +++ b/src/idiomatic/foundations-api-design/predictable-api/common-traits/07-serde.md @@ -0,0 +1,36 @@ +--- +minutes: 5 +--- + +Serialize/Deserialize style traits + +Crates like `serde` can implement serialization automatically. + +Derivable: ✅ When to implement: Almost always. + +```rust,no_compile +#[derive(Serialize, Deserialize)] +struct ExtraData { + fav_color: String, + name_of_dog: String, +} + +#[derive(Serialize, Deserialize)] +struct Data { + name: String, + age: usize, + extra_data: ExtraData, +} +``` + +
+- Provides serialization and deserialization functionality for a type. + +- When not to implement: If a type contains sensitive data that should not be + erroneously saved to disk or sent over a network, consider not implementing + Serialize/Deserialize for that type. + + Shares security concerns with `Debug`, but given serialization is often used + in networking there can be higher stakes. + +
diff --git a/src/idiomatic/foundations-api-design/predictable-api/common-traits/08-from-into.md b/src/idiomatic/foundations-api-design/predictable-api/common-traits/08-from-into.md new file mode 100644 index 000000000000..4bb6cb9ac8cb --- /dev/null +++ b/src/idiomatic/foundations-api-design/predictable-api/common-traits/08-from-into.md @@ -0,0 +1,58 @@ +--- +minutes: 5 +--- + +# From & Into + +Conversion from one type to another. + +Derivable: ❌, without crates like `derive_more`. When to implement: As-needed +and convenient. + +```rust +pub struct ObviousImplementation(String); + +impl From for ObviousImplementation { + fn from(value: String) -> Self { + ObviousImplementation(value) + } +} + +impl From<&str> for ObviousImplementation { + fn from(value: &str) -> Self { + ObviousImplementation(value.to_owned()) + } +} + +fn main() { + // From String + let obvious1 = ObviousImplementation::from("Hello, obvious!".to_string()); + // From &str + let obvious2 = ObviousImplementation::from("Hello, obvious!"); + // A From implementation implies an Into implementation, &str.into() -> + // ObviousImplementation + let obvious3: ObviousImplementation = "Hello, implementation!".into(); +} +``` + +
+- Provides conversion functionality to types. + +- The two traits exist to express different areas you'll find conversion in + codebases. + +- `From` provides a constructor-style function, whereas into provides a method + on an existing value. + +- Prefer writing `From` implementations for a type you're authoring instead + of `Into`. + + The `Into` trait is implemented for any type that implements `From` + automatically. + + `Into` is preferred as a trait bound for arguments to functions for clarity of + intent for what the function can take. + + `T: Into` has clearer intent than `String: From`. + +
diff --git a/src/idiomatic/foundations-api-design/predictable-api/common-traits/09-try-from-into.md b/src/idiomatic/foundations-api-design/predictable-api/common-traits/09-try-from-into.md new file mode 100644 index 000000000000..fd370bce9698 --- /dev/null +++ b/src/idiomatic/foundations-api-design/predictable-api/common-traits/09-try-from-into.md @@ -0,0 +1,45 @@ +--- +minutes: 5 +--- + +# TryFrom/TryInto + +Fallible conversion from one type to another. + +Derivable: ❌ When to implement: As-needed. + +```rust +#[derive(Debug)] +pub struct InvalidNumber; + +#[derive(Debug)] +pub struct DivisibleByTwo(usize); + +impl TryFrom for DivisibleByTwo { + type Error = InvalidNumber; + fn try_from(value: usize) -> Result { + if value.rem_euclid(2) == 0 { + Ok(DivisibleByTwo(value)) + } else { + Err(InvalidNumber) + } + } +} + +fn main() { + let success: Result = 4.try_into(); + dbg!(success); + let fail: Result = 5.try_into(); + dbg!(fail); +} +``` + +
+- Provides conversion that can fail, returning a result type. + +- Like `From`/`Into`, prefer implementing `TryFrom` for types rather than + `TryInto`. + +- Implementations can specify what the error type of the `Result`. + +
diff --git a/src/idiomatic/foundations-api-design/predictable-api/common-traits/10-display.md b/src/idiomatic/foundations-api-design/predictable-api/common-traits/10-display.md new file mode 100644 index 000000000000..e1eacb3a0cd3 --- /dev/null +++ b/src/idiomatic/foundations-api-design/predictable-api/common-traits/10-display.md @@ -0,0 +1,46 @@ +--- +minutes: 5 +--- + +# Display + +"Write to string" trait, prioritizing readability for an end user. + +Derivable: ❌, without crates like `derive_more`. When to implement: As-needed, +for errors and other types that an end-user will see. + +```rust +pub enum NetworkError { + HttpCode(u16), + WhaleBitTheUnderseaCable, +} + +impl std::fmt::Display for NetworkError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + HttpCode(code) => write!(f, "HTTP Error code {code}"), + WhaleBitTheUnderseaCable => { + write!(f, "Whale attack detected – call Ishmael") + } + } + } +} + +impl std::error::Error for NetworkError {} +``` + +
+- A trait similar to `Debug`, but with a focus on end-user readability. + +- Prerequisite for the `Error` trait. + + If implementing for an error type, focus on providing a descriptive error for + users and programmers other than you. + +- Same security considerations as Debug, consider the ways that sensitive data + could be exposed in UI or logs. + +- Types that implement `Display` automatically have `ToString` implemented for + them. + +
diff --git a/src/idiomatic/foundations-api-design/predictable-api/naming-conventions.md b/src/idiomatic/foundations-api-design/predictable-api/naming-conventions.md new file mode 100644 index 000000000000..91e306686e3b --- /dev/null +++ b/src/idiomatic/foundations-api-design/predictable-api/naming-conventions.md @@ -0,0 +1,20 @@ +--- +minutes: 2 +--- + +# Naming Conventions + +
+- One core component of readability and predictability is the way function names are composed. + +A formal and consistently-applied naming convention lets developers treat names +like a domain-specific language and quickly understand the functionality and use +cases of a method. + +Rust's community developed naming conventions early, making them mostly +consistent in places like the standard library. + +- Here we'll learn common components of rust method names, giving examples from + the standard library and some context to go with them. + +
diff --git a/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/01-get.md b/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/01-get.md new file mode 100644 index 000000000000..25aac6450d88 --- /dev/null +++ b/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/01-get.md @@ -0,0 +1,31 @@ +--- +minutes: 2 +--- + +# Get + +Getting an element from a collection or container. + +```rust +// Safe, fallible indexing. +let items: Vec = vec![1, 2, 3]; +let option = items.get(0); // &Vec -> Option<&u8> +assert_eq!(Some(1), option); +let failed_option = items.get(1000); // &Vec -> Option<&u8> +assert_eq!(None, option); +``` + +
+- Gets are trivial, they get a value! + +Immutable by default, for the most part. + +Should not panic. May return an option or result, depending on the framework. + +- Not for fields! + + For private fields you don't want users to have direct, assign-level access t + a method with a more descriptive name (or the same name as the field) is + preferred. + +
diff --git a/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/02-push.md b/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/02-push.md new file mode 100644 index 000000000000..9edc82e9822c --- /dev/null +++ b/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/02-push.md @@ -0,0 +1,29 @@ +--- +minutes: 2 +--- + +# Push + +Common on array-like structures. + +```rust +use std::collections::VecDeque; + +let mut items: Vec = Vec::new(); +items.push(42); +let mut items_queue: VecDeque = VecDeque::new(); +items_queue.push_front(233); +// [233] +items_queue.push_back(42); +// [233, 42] +items_queue.push_front(128); +// [128, 233, 42] +dbg!(items_queue); +``` + +
+- Modifies an array-like structure by adding an element. + +Needs mutable access! + +
diff --git a/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/03-is.md b/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/03-is.md new file mode 100644 index 000000000000..f03e3432562b --- /dev/null +++ b/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/03-is.md @@ -0,0 +1,27 @@ +--- +minutes: 2 +--- + +# Is + +Check a condition about a datatype. + +```rust +// TODO: Should this just be no-compile versions that +dbg!("".is_empty()); +dbg!(vec![1u32].is_empty()); +dbg!(f32::NAN.is_nan()); +// No is_not_nan method, don't write these kinds of methods! +dbg!(!0.99.is_nan()); +dbg!(64u32.is_power_of_two()); +``` + +
+- A boolean condition on a value. + +`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_`. + +
diff --git a/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/04-mut.md b/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/04-mut.md new file mode 100644 index 000000000000..eac0940c1f01 --- /dev/null +++ b/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/04-mut.md @@ -0,0 +1,24 @@ +--- +minutes: 2 +--- + +# Mut + +Suffix for access-style methods. + +```rust +Vec::get_mut +// Iterate over a slice by mutable reference, being able to mutate +// items in the iterator as you iterate over them. +slice::iter_mut +RefCell::get_mut +``` + +
+- 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. + +
diff --git a/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/05-try.md b/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/05-try.md new file mode 100644 index 000000000000..12b8b3441343 --- /dev/null +++ b/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/05-try.md @@ -0,0 +1,27 @@ +--- +minutes: 2 +--- + +# Try + +Prefix for fallible methods that return a `Result`. + +```rust +``` + +
+- Prefix for methods that can fail, returning a `Result`. + +- `TryFrom` is a `From`-like trait for types whose single-value constructors + might fail in some way. + +- Ask: Why aren't `Vec::get` and other similar methods `try_get`? + + There's only one possible error with get-style methods, out-of-bounds or + key-does-not-exist style access errors. + + Also: get-style methods will be used frequently with data types like hash + maps, sets. `get` is shorter and faster to scan visually than try_get, if try + were more prolific. + +
diff --git a/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/06-with.md b/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/06-with.md new file mode 100644 index 000000000000..89bea4fc556a --- /dev/null +++ b/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/06-with.md @@ -0,0 +1,31 @@ +--- +minutes: 5 +--- + +# With + +Prefix for builder-style configuration. + +```rust +{Vec, BTreeSet}::with_capacity +PathBuf::with_extension +PathBuf::with_file_name +``` + +
+- Prefix for methods that set something internally. + +Can be constructors, builders, or setters. + +- Constructor-style `with` methods usually set one specific field but leave + everything else "default" + + `with_capacity` allocates enough space for the number of elements given, but + does not otherwise add anything to the data structure. + +- When `with` methods take an owned value, they're builder-style. + +- When `with` methods take a reference, like pathbuf's `with` methods, they + return a new owned value while the original value remains. + +
diff --git a/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/07-from.md b/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/07-from.md new file mode 100644 index 000000000000..9bbe0c29825e --- /dev/null +++ b/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/07-from.md @@ -0,0 +1,25 @@ +--- +minutes: 2 +--- + +# From + +Prefix for a constructor-style function. + +```rust +// TODO: more examples +Vec::from_raw_parts, from_iter, from_le_bytes +``` + +
+- 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 + for `from` is transformation of one data type to another. + +- Ask: What will `from_iter` do? + +
diff --git a/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/08-into.md b/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/08-into.md new file mode 100644 index 000000000000..aa5f522fc5b5 --- /dev/null +++ b/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/08-into.md @@ -0,0 +1,29 @@ +--- +Minutes: 2 +--- + +# Into + +Prefix for a type transformation style method. + +```rust +Vec::into_parts +Cell::into_inner +IntoIter::into_iter +``` + +
+- 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. + +- corollary to `From` + +- `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_parts` do? + +
diff --git a/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/09-owned.md b/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/09-owned.md new file mode 100644 index 000000000000..91a570d35ff4 --- /dev/null +++ b/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/09-owned.md @@ -0,0 +1,21 @@ +--- +minutes: 2 +--- + +# Owned + +Suffix for functions and methods about owned values in a context where +references are common. + +``` +String::to_owned +Cow::into_owned +``` + +
+- Most often seen in to_owned methods, especially on strings. + +Some exceptions, such as Cow (copy on write) having an `into_owned` method that +consumes the Cow and produces an owned value via the `ToOwned` trait. + +
diff --git a/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/10-by.md b/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/10-by.md new file mode 100644 index 000000000000..e8242a604009 --- /dev/null +++ b/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/10-by.md @@ -0,0 +1,25 @@ +--- +minutes: 2 +--- + +# By + +Component for methods that take a custom projection or comparison function. + +```rust +slice::sort_by +// caches the projection +slice::sort_by_key +Iterator::min_by +``` + +
+- Method will take a projection function. + +- 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. + +- Contradiction: `advance_by` iterator method (nightly feature) + +
diff --git a/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/11-unchecked.md b/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/11-unchecked.md new file mode 100644 index 000000000000..a07e7e190872 --- /dev/null +++ b/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/11-unchecked.md @@ -0,0 +1,25 @@ +--- +minutes: 2 +--- + +# Unchecked + +Component for methods and functions where users need to manage safety manually. + +```rust +NonNull::new_unchecked +Vec::split_at_unchecked +``` + +
+- Function is likely only callable in an unsafe block, or does not perform any runtime checks even in debug compilation. + +- Users must be careful when using these functions, as they are responsible for + making sure invariants are maintained. + +- Inputs that do not maintain expected invariants, like passing a nullptr to + NonNull::new_unchecked, will result in undefined behavior. + +- Methods with this should have a "safety" comment in their documentation + +
diff --git a/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/12-to.md b/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/12-to.md new file mode 100644 index 000000000000..26a7d756e480 --- /dev/null +++ b/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/12-to.md @@ -0,0 +1,29 @@ +--- +minutes: 2 +--- + +# To + +Prefix to a function that takes a borrowed value and creates an owned value + +```rust +String::to_owned // &str -> String (&str is not consumed) +``` + +
+- Method for a function from a borrowed value to owned value. + +Not an escape hatch to make something borrowed into something owned, instead +creates a new owned value. + +May transform the data in some way! May return an entirely different type. This +is what makes it different from clone. + +Example: to_uppercase creates a version of a string with all uppercase letters. + +- Tends to not consume source value. + +- Also seen in functions that convert the endianness of primitives, or copy and + expose the value of a newtype. + +
diff --git a/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/13-as-and-ref.md b/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/13-as-and-ref.md new file mode 100644 index 000000000000..b702260ce397 --- /dev/null +++ b/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/13-as-and-ref.md @@ -0,0 +1,38 @@ +--- +minutes: 5 +--- + +# As and Ref + +As is a prefix for getting a reference to something internal. Ref is a suffix. + +```rust,no_compile +Option::as_ref // &Option -> Option<&T> +Option::as_slice // &Option -> &[T] (0 or 1 elements) +OwnedFd::as_fd // &'a OwnedFd -> BorrowedFd<'a> (we'll see this later!) +Rc::as_ptr // &Rc -> *const T +Vec::as_ptr // &Vec -> *const T +``` + +
+- Method for getting a reference-style value from an owned or borrowed value. + +- Often used for getting something internal to a type. + + Collection and smart pointer types often have an `as_ptr` method, giving + access to the pointer of the value they contain. + +- Does not consume the value! Main difference between this and `to` or `into` + functions. + +- Highlight: OwnedFd::as_fd duplicates a file descriptor while tying ownership + of that descriptor to the original OwnedFd. + + This gets covered later! Don't worry about this for now. + +- Ref is a common suffix with `as`-named functions. + + `as_ref` is often a transformation of a reference to a container type (such as + option) to an owned container of reference types. + +
diff --git a/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/14-mini-exercise.md b/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/14-mini-exercise.md new file mode 100644 index 000000000000..bf5a3a2ce2a0 --- /dev/null +++ b/src/idiomatic/foundations-api-design/predictable-api/naming-conventions/14-mini-exercise.md @@ -0,0 +1,32 @@ +--- +minutes: 10 +--- + +Mini-exercise + +1. What do these names imply they do? +2. What should we name these signatures? + +```rust,compile_fail +// What are the types for these methods? +Option::is_some // ? +Slice::get // ? +Slice::get_unchecked_mut // ? +Option::as_ref // ? + +// What should we name methods with these types? +fn ____(String) -> Self; +fn ____(&self) -> Option<&InnerType>; // details for InnerType do not matter. +fn ____(self, String) -> Self; +fn ____(&mut self) -> Option<&mut InnerType>; +``` + +
+ +- Go through the methods in the example with the class and discuss what the + types of the functions should be. + +- Go through the unnamed methods and brainstorm what names those methods should + have. + +