From 1508dbb9f037324141ea08bc92a9664c02d3f11a Mon Sep 17 00:00:00 2001
From: LukeMathWalker <20745048+LukeMathWalker@users.noreply.github.com>
Date: Tue, 1 Jul 2025 15:56:39 +0200
Subject: [PATCH] Introduce 'Idiomatic Rust' module
---
src/SUMMARY.md | 8 +++
src/idiomatic/leveraging-the-type-system.md | 47 ++++++++++++++++++
.../newtype-pattern.md | 49 +++++++++++++++++++
src/idiomatic/welcome.md | 26 ++++++++++
4 files changed, 130 insertions(+)
create mode 100644 src/idiomatic/leveraging-the-type-system.md
create mode 100644 src/idiomatic/leveraging-the-type-system/newtype-pattern.md
create mode 100644 src/idiomatic/welcome.md
diff --git a/src/SUMMARY.md b/src/SUMMARY.md
index 4caccd92..dedf9028 100644
--- a/src/SUMMARY.md
+++ b/src/SUMMARY.md
@@ -429,6 +429,14 @@
---
+# Idiomatic Rust
+
+- [Welcome](idiomatic/welcome.md)
+- [Leveraging the Type System](idiomatic/leveraging-the-type-system.md)
+ - [Newtype Pattern](idiomatic/leveraging-the-type-system/newtype-pattern.md)
+
+---
+
# Final Words
- [Thanks!](thanks.md)
diff --git a/src/idiomatic/leveraging-the-type-system.md b/src/idiomatic/leveraging-the-type-system.md
new file mode 100644
index 00000000..21e1fae5
--- /dev/null
+++ b/src/idiomatic/leveraging-the-type-system.md
@@ -0,0 +1,47 @@
+---
+minutes: 5
+---
+
+# Leveraging the Type System
+
+Rust's type system is _expressive_.\
+We can use types and traits to build abstractions that make our code harder to
+misuse. In some cases, we can even go as far as enforcing correctness at
+_compile-time_. Quite often, these abstractions have no runtime
+overhead[^zero-cost].
+
+The type system can also be used to model concepts and constraints from your
+business domain. By designing our types carefully, we can improve the clarity
+and maintainability of the entire codebase.
+
+
+
+Additional items speaker may mention:
+
+- Rust's type system borrows a lot of ideas from functional programming
+ languages.\
+ For example, Rust's enums are known as "algebraic data types" in languages
+ like Haskell and OCaml. You can take inspiration from learning material geared
+ towards functional languages when looking for guidance on how to design with
+ types. ["Domain Modeling Made Functional"][1] is a great resource on the
+ topic, with examples written in F#.
+
+- Despite its functional roots, functional design patterns don't translate as-is
+ to Rust. For instance, extensive use of higher-kinded functions and types can
+ result in code that is harder to read and maintain. Design patterns in Rust
+ must take into account (and leverage!) the granular control over mutability
+ that comes with its borrow-checker.
+
+- The same caution should be applied to object-oriented design patterns. Rust
+ doesn't support inheritance, and object boundaries must be mindful of the
+ constraints introduced by the borrow-checker.
+
+
+
+{{%segment outline}}
+
+[1]: https://pragprog.com/titles/swdddf/domain-modeling-made-functional/
+
+[^zero-cost]: They often referred to as "zero-cost abstractions", although the
+ label can be misleading: the impact on compile times and code complexity may
+ be significant.
diff --git a/src/idiomatic/leveraging-the-type-system/newtype-pattern.md b/src/idiomatic/leveraging-the-type-system/newtype-pattern.md
new file mode 100644
index 00000000..e6c04f58
--- /dev/null
+++ b/src/idiomatic/leveraging-the-type-system/newtype-pattern.md
@@ -0,0 +1,49 @@
+---
+minutes: 5
+---
+
+# Newtype Pattern
+
+A _newtype_ is a wrapper around an existing type, often a primitive:
+
+```rust
+/// A unique user identifier, implemented as a newtype around `u64`.
+pub struct UserId(u64);
+```
+
+Unlike type aliases, newtypes aren't interchangeable with the wrapped type:
+
+```rust,compile_fail
+# pub struct UserId(u64);
+fn double(n: u64) -> u64 {
+ n * 2
+}
+
+// This doesn't compile ❌
+double(UserId(1));
+```
+
+The Rust compiler won't implicitly convert to (or from) the underlying type.\
+It won't let you use methods or operators defined on the underlying type either:
+
+```rust,compile_fail
+# pub struct UserId(u64);
+// This doesn't compile ❌
+assert_ne!(UserId(1), UserId(2));
+```
+
+
+
+- Run the example to show students the error message from the compiler.
+
+- Modify the example to use a typealias instead of a newtype, such as
+ `type MessageId = u64`. The modified example should compile, thus highlighting
+ the differences between the two approaches.
+
+- Stress that newtypes, out of the box, have no behaviour attached to them. You
+ need to be intentional about which methods and operators you are willing to
+ forward from the underlying type. In our `UserId` example, it is reasonable to
+ allow comparisons between `UserId`s, but it wouldn't make sense to allow
+ arithmetic operations like addition or subtraction.
+
+
diff --git a/src/idiomatic/welcome.md b/src/idiomatic/welcome.md
new file mode 100644
index 00000000..e507c546
--- /dev/null
+++ b/src/idiomatic/welcome.md
@@ -0,0 +1,26 @@
+---
+course: Idiomatic Rust
+session: Morning
+target_minutes: 180
+---
+
+# Welcome to Idiomatic Rust
+
+[Rust Fundamentals](../welcome-day-1.md) introduced Rust syntax and core
+concepts. We now want to go one step further: how do you use Rust _effectively_
+in your projects? What does _idiomatic_ Rust look like?
+
+This course is opinionated: we will nudge you towards some patterns, and away
+from others. Nonetheless, we do recognize that some projects may have different
+needs. We always provide the necessary information to help you make informed
+decisions within the context and constraints of your own projects.
+
+> ⚠️ This course is under **active development**.
+>
+> The material may change frequently and there might be errors that have not yet
+> been spotted. Nonetheless, we encourage you to browse through and provide
+> early feedback!
+
+## Schedule
+
+{{%session outline}}