Skip to content

Commit 1508dbb

Browse files
Introduce 'Idiomatic Rust' module
1 parent 010b443 commit 1508dbb

File tree

4 files changed

+130
-0
lines changed

4 files changed

+130
-0
lines changed

src/SUMMARY.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,14 @@
429429

430430
---
431431

432+
# Idiomatic Rust
433+
434+
- [Welcome](idiomatic/welcome.md)
435+
- [Leveraging the Type System](idiomatic/leveraging-the-type-system.md)
436+
- [Newtype Pattern](idiomatic/leveraging-the-type-system/newtype-pattern.md)
437+
438+
---
439+
432440
# Final Words
433441

434442
- [Thanks!](thanks.md)
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
---
2+
minutes: 5
3+
---
4+
5+
# Leveraging the Type System
6+
7+
Rust's type system is _expressive_.\
8+
We can use types and traits to build abstractions that make our code harder to
9+
misuse. In some cases, we can even go as far as enforcing correctness at
10+
_compile-time_. Quite often, these abstractions have no runtime
11+
overhead[^zero-cost].
12+
13+
The type system can also be used to model concepts and constraints from your
14+
business domain. By designing our types carefully, we can improve the clarity
15+
and maintainability of the entire codebase.
16+
17+
<details>
18+
19+
Additional items speaker may mention:
20+
21+
- Rust's type system borrows a lot of ideas from functional programming
22+
languages.\
23+
For example, Rust's enums are known as "algebraic data types" in languages
24+
like Haskell and OCaml. You can take inspiration from learning material geared
25+
towards functional languages when looking for guidance on how to design with
26+
types. ["Domain Modeling Made Functional"][1] is a great resource on the
27+
topic, with examples written in F#.
28+
29+
- Despite its functional roots, functional design patterns don't translate as-is
30+
to Rust. For instance, extensive use of higher-kinded functions and types can
31+
result in code that is harder to read and maintain. Design patterns in Rust
32+
must take into account (and leverage!) the granular control over mutability
33+
that comes with its borrow-checker.
34+
35+
- The same caution should be applied to object-oriented design patterns. Rust
36+
doesn't support inheritance, and object boundaries must be mindful of the
37+
constraints introduced by the borrow-checker.
38+
39+
</details>
40+
41+
{{%segment outline}}
42+
43+
[1]: https://pragprog.com/titles/swdddf/domain-modeling-made-functional/
44+
45+
[^zero-cost]: They often referred to as "zero-cost abstractions", although the
46+
label can be misleading: the impact on compile times and code complexity may
47+
be significant.
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
---
2+
minutes: 5
3+
---
4+
5+
# Newtype Pattern
6+
7+
A _newtype_ is a wrapper around an existing type, often a primitive:
8+
9+
```rust
10+
/// A unique user identifier, implemented as a newtype around `u64`.
11+
pub struct UserId(u64);
12+
```
13+
14+
Unlike type aliases, newtypes aren't interchangeable with the wrapped type:
15+
16+
```rust,compile_fail
17+
# pub struct UserId(u64);
18+
fn double(n: u64) -> u64 {
19+
n * 2
20+
}
21+
22+
// This doesn't compile ❌
23+
double(UserId(1));
24+
```
25+
26+
The Rust compiler won't implicitly convert to (or from) the underlying type.\
27+
It won't let you use methods or operators defined on the underlying type either:
28+
29+
```rust,compile_fail
30+
# pub struct UserId(u64);
31+
// This doesn't compile ❌
32+
assert_ne!(UserId(1), UserId(2));
33+
```
34+
35+
<details>
36+
37+
- Run the example to show students the error message from the compiler.
38+
39+
- Modify the example to use a typealias instead of a newtype, such as
40+
`type MessageId = u64`. The modified example should compile, thus highlighting
41+
the differences between the two approaches.
42+
43+
- Stress that newtypes, out of the box, have no behaviour attached to them. You
44+
need to be intentional about which methods and operators you are willing to
45+
forward from the underlying type. In our `UserId` example, it is reasonable to
46+
allow comparisons between `UserId`s, but it wouldn't make sense to allow
47+
arithmetic operations like addition or subtraction.
48+
49+
</details>

src/idiomatic/welcome.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
---
2+
course: Idiomatic Rust
3+
session: Morning
4+
target_minutes: 180
5+
---
6+
7+
# Welcome to Idiomatic Rust
8+
9+
[Rust Fundamentals](../welcome-day-1.md) introduced Rust syntax and core
10+
concepts. We now want to go one step further: how do you use Rust _effectively_
11+
in your projects? What does _idiomatic_ Rust look like?
12+
13+
This course is opinionated: we will nudge you towards some patterns, and away
14+
from others. Nonetheless, we do recognize that some projects may have different
15+
needs. We always provide the necessary information to help you make informed
16+
decisions within the context and constraints of your own projects.
17+
18+
> ⚠️ This course is under **active development**.
19+
>
20+
> The material may change frequently and there might be errors that have not yet
21+
> been spotted. Nonetheless, we encourage you to browse through and provide
22+
> early feedback!
23+
24+
## Schedule
25+
26+
{{%session outline}}

0 commit comments

Comments
 (0)