From 6b041937356522e770fd3cfc0399ed0a1e65f95b Mon Sep 17 00:00:00 2001 From: Glen De Cauwsemaecker Date: Sun, 3 Aug 2025 20:32:50 +0200 Subject: [PATCH] improve typestate pattern slides --- .../leveraging-the-type-system/typestate-pattern.md | 3 ++- .../typestate-pattern/typestate-advanced.md | 3 --- .../typestate-pattern/typestate-example.md | 11 ++++++----- .../typestate-pattern/typestate-generics.md | 4 ++-- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/idiomatic/leveraging-the-type-system/typestate-pattern.md b/src/idiomatic/leveraging-the-type-system/typestate-pattern.md index 627101c8..bfe86452 100644 --- a/src/idiomatic/leveraging-the-type-system/typestate-pattern.md +++ b/src/idiomatic/leveraging-the-type-system/typestate-pattern.md @@ -83,6 +83,7 @@ serialize struct start system. In the next slide, we will apply the **typestate pattern** to enforce correct - usage at compile time and make invalid states unrepresentable. + usage at compile time and make it impossible to call incompatible methods or + forget to do a required action. diff --git a/src/idiomatic/leveraging-the-type-system/typestate-pattern/typestate-advanced.md b/src/idiomatic/leveraging-the-type-system/typestate-pattern/typestate-advanced.md index 0f95b5b5..fd10ef5e 100644 --- a/src/idiomatic/leveraging-the-type-system/typestate-pattern/typestate-advanced.md +++ b/src/idiomatic/leveraging-the-type-system/typestate-pattern/typestate-advanced.md @@ -60,9 +60,6 @@ impl SerializeList { - However, this introduces both **duplication** and **structural complexity**. - `SerializeStructProperty` and `SerializeList` now share similar logic (e.g. - adding strings, nested structs, or nested lists). - - Even more critically, we now hit a **type system limitation**: we cannot cleanly express what `finish()` should return without duplicating variants for every nesting context (e.g. root, struct, list). diff --git a/src/idiomatic/leveraging-the-type-system/typestate-pattern/typestate-example.md b/src/idiomatic/leveraging-the-type-system/typestate-pattern/typestate-example.md index bde35052..9a22e3ab 100644 --- a/src/idiomatic/leveraging-the-type-system/typestate-pattern/typestate-example.md +++ b/src/idiomatic/leveraging-the-type-system/typestate-pattern/typestate-example.md @@ -17,7 +17,7 @@ struct SerializeStruct { impl Serializer { fn serialize_struct(mut self, name: &str) -> SerializeStruct { - let _ = writeln!(&mut self.output, "{name} {{"); + writeln!(&mut self.output, "{name} {{").unwrap(); SerializeStruct { serializer: self } } @@ -28,7 +28,7 @@ impl Serializer { impl SerializeStruct { fn serialize_field(mut self, key: &str, value: &str) -> Self { - let _ = writeln!(&mut self.serializer.output, " {key}={value};"); + writeln!(&mut self.serializer.output, " {key}={value};").unwrap(); self } @@ -62,8 +62,9 @@ fn main() { ```bob +------------+ serialize struct +-----------------+ -| Serializer +-------------------->| SerializeStruct |<-------+ -+--+---------+ +-+-----+---------+ | +| Serializer | ------------------> | SerializeStruct | <------+ ++------------+ +-----------------+ | + | | ^ | | | | | finish struct | | serialize field | | +-----------------------------+ +------------------+ @@ -81,7 +82,7 @@ fn main() { related to serializing struct fields. - The original `Serializer` is no longer accessible — preventing us from - mixing modes (like writing a tuple or primitive mid-struct) or calling + mixing modes (such as starting another _struct_ mid-struct) or calling `finish()` too early. - Only after calling `.finish_struct()` do we receive the `Serializer` back. diff --git a/src/idiomatic/leveraging-the-type-system/typestate-pattern/typestate-generics.md b/src/idiomatic/leveraging-the-type-system/typestate-pattern/typestate-generics.md index 57af8c1d..9a839578 100644 --- a/src/idiomatic/leveraging-the-type-system/typestate-pattern/typestate-generics.md +++ b/src/idiomatic/leveraging-the-type-system/typestate-pattern/typestate-generics.md @@ -176,7 +176,7 @@ fn main() {
- The full code for this example is available - [in the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=48b106089ca600453f3ed00a0a31af26) + [in the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=48b106089ca600453f3ed00a0a31af26). - By using generics to track the parent context, we can construct arbitrarily nested serializers that enforce valid transitions between struct, list, and @@ -234,7 +234,7 @@ finish | | +-------------------------------+ struct - Of course, this pattern isn't a silver bullet. It still allows issues like: - Empty or invalid property names (which can be fixed using [the newtype pattern](../newtype-pattern.md)) - - Duplicate property names (which could be tracked in `Struct` or handled + - Duplicate property names (which could be tracked in `Struct` and handled via `Result`) - If validation failures occur, we can also change method signatures to return a