>`](https://doc.rust-lang.org/book/ch16-03-shared-state.html) |
+| Const reference | `const &T` | `&T` |
+| Mutable reference | `&T` | `&mut T` |
+| Const observer pointer | `const *T` | `&T` |
+| Mutable observer pointer | `*T` | `&mut T` |
In C++, the thread safety of `std::shared_ptr` is more nuanced than it appears
in this table (e.g., some uses may require `std::atomic`). However, in safe Rust
diff --git a/src/idioms/varargs.md b/src/idioms/varargs.md
deleted file mode 100644
index f35a073..0000000
--- a/src/idioms/varargs.md
+++ /dev/null
@@ -1 +0,0 @@
-# Varargs
diff --git a/src/optimizations/rvo_and_placement_new.md b/src/optimizations/rvo_and_placement_new.md
deleted file mode 100644
index 46c0684..0000000
--- a/src/optimizations/rvo_and_placement_new.md
+++ /dev/null
@@ -1 +0,0 @@
-# NRVO, RVO, and placement new
diff --git a/src/patterns/adapter.md b/src/patterns/adapter.md
index 59f19e2..f936028 100644
--- a/src/patterns/adapter.md
+++ b/src/patterns/adapter.md
@@ -112,3 +112,5 @@ fn main() {
The `map` method returns a different type than `iter`, but `middle` can be
called on the result of either one.
+
+{{#quiz adapter.toml}}
diff --git a/src/patterns/adapter.toml b/src/patterns/adapter.toml
new file mode 100644
index 0000000..6a864d2
--- /dev/null
+++ b/src/patterns/adapter.toml
@@ -0,0 +1,43 @@
+[[questions]]
+type = "MultipleChoice"
+prompt.prompt = """
+Consider a situation where you are working with a type `Circle` and a trait
+`Shape`. The type and trait are each defined in one of:
+
+- the current crate,
+- a dependency crate `crate_a` of the current crate, or
+- a depedency `crate_b` of the current crate.
+
+For which situations is the adapter pattern necessary in Rust?
+"""
+prompt.distractors = [
+"""
+`Circle` and `Shape` are both defined in the current crate.
+""",
+"""
+`Circle` is defined in the current crate, and and `Shape` is defined in `crate_a`.
+""",
+"""
+`Shape` is defined in the current crate, and and `Circle` is defined in `crate_a`.
+"""
+]
+answer.answer = [
+"""
+`Circle` and `Shape` are both defined in `crate_a`.
+""",
+"""
+`Circle` is defined in `crate_a`, and `Shape` is defined in `crate_b`.
+"""
+]
+context = """
+The apdapter pattern is needed when the orphan rule prevents implementing a
+trait for a type.
+
+The [orphan
+rule](https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules)
+says that a at least one of the trait or a type in the trait implementation
+needs to be defined in the current crate. When at least one of `Shape` or
+`Circle` is defined in the current crate, the orphan rule does not prevent the
+implementation.
+"""
+id = "b6394504-9fdb-49c8-88c0-046c42f74287"
diff --git a/src/patterns/pimpl.md b/src/patterns/pimpl.md
index c96ba11..22f75cc 100644
--- a/src/patterns/pimpl.md
+++ b/src/patterns/pimpl.md
@@ -1 +1,17 @@
-# Pointer-to-implementation (PImpl)
+# Pointer-to-implementation (PIMPL)
+
+The [PIMPL pattern](https://en.cppreference.com/w/cpp/language/pimpl.html) in
+C++ is usually used for the purpose of improving compilation times by removing
+implementation details from the ABI of a translation unit. It also can be used
+to hide implementation details that otherwise would be exposed in a header file.
+
+In Rust, the unit of separate compilation is the crate, rather than the file or
+module. Within a crate, the compiler minimizes compilation times via incremental
+compilation, rather than via separate compilation. Between crates, there is no
+guarantee of Rust-native ABI stability, so if an upstream crate changes,
+downstream crates need to be recompiled. Thus, for performance purposes, the
+PIMPL pattern does not apply.
+
+For the hiding of implementation details, [instead of excluding details from a
+header file, modules can be used to control
+visibility](../idioms/encapsulation.md).
diff --git a/src/patterns/visitor.md b/src/patterns/visitor.md
new file mode 100644
index 0000000..34adff3
--- /dev/null
+++ b/src/patterns/visitor.md
@@ -0,0 +1,754 @@
+# Visitor pattern and double dispatch
+
+In C++ the visitor pattern is typically used to enable adding behaviors to a
+type without modifying the class definitions. In Rust, the same goal is
+conventionally accomplished by using Rust enums, which resemble C++ [tagged
+unions](../idioms/data_modeling/tagged_unions.md). While the chapter on tagged
+unions compares using Rust enums with C++ `std::variant`, this chapter [compares
+using the visitor pattern in C++ with using Rust
+enums](#use-a-rust-enum-instead).
+
+Since the visitor pattern and double dispatch may be useful for other purposes
+as well, a [Rust visitor pattern version of the example](#visitors) is also
+given.
+
+Extensions of the visitor pattern are sometimes used in C++ to make it possible
+to extend both data and behavior without modifying the original definitions
+(i.e., to solve [the expression
+problem](https://cs.brown.edu/~sk/Publications/Papers/Published/kff-synth-fp-oo/)).
+Other approaches, enabled by Rust's traits and generics, are [more likely to be
+used in Rust](#varying-data-and-behavior).
+
+## Use a Rust enum instead
+
+For the first case, where the variants are fixed but behaviors are not, the
+idiomatic approach in Rust is to implement the data structure as an enum instead
+of as many structs with a common interface. This is similar to using
+`std::variant` in C++.
+
+
+
+```cpp
+#include
+#include
+#include
+#include
+#include
+
+// Declare types that visitor can visit
+class Lit;
+class Plus;
+class Var;
+class Let;
+
+// Define abstract class for visitor
+struct Visitor {
+ virtual void visit(Lit &e) = 0;
+ virtual void visit(Plus &e) = 0;
+ virtual void visit(Var &e) = 0;
+ virtual void visit(Let &e) = 0;
+ virtual ~Visitor() = default;
+
+protected:
+ Visitor() = default;
+};
+
+// Define abstract class for expressions
+struct Exp {
+ virtual void accept(Visitor &v) = 0;
+ virtual ~Exp() = default;
+};
+
+// Implement each expression variant
+struct Lit : public Exp {
+ int value;
+
+ Lit(int value) : value(value) {}
+
+ void accept(Visitor &v) override {
+ v.visit(*this);
+ }
+};
+
+struct Plus : public Exp {
+ std::unique_ptr lhs;
+ std::unique_ptr rhs;
+
+ Plus(std::unique_ptr lhs,
+ std::unique_ptr rhs)
+ : lhs(std::move(lhs)), rhs(std::move(rhs)) {
+ }
+
+ void accept(Visitor &v) override {
+ v.visit(*this);
+ }
+};
+
+struct Var : public Exp {
+ std::string name;
+
+ Var(std::string name) : name(name) {}
+
+ void accept(Visitor &v) override {
+ v.visit(*this);
+ }
+};
+
+struct Let : public Exp {
+ std::string name;
+ std::unique_ptr exp;
+ std::unique_ptr body;
+
+ Let(std::string name, std::unique_ptr exp,
+ std::unique_ptr body)
+ : name(std::move(name)),
+ exp(std::move(exp)),
+ body(std::move(body)) {}
+
+ void accept(Visitor &v) override {
+ v.visit(*this);
+ }
+};
+
+// Define Visitor for evaluating expressions
+
+// Exception for representing expression
+// evaluation errors
+struct UnknownVar : std::exception {
+ std::string name;
+
+ UnknownVar(std::string name) : name(name) {}
+
+ const char *what() const noexcept override {
+ return "Unknown variable";
+ }
+};
+
+// Define type for evaluation environment
+using Env = std::unordered_map;
+
+// Define evaluator
+struct EvalVisitor : public Visitor {
+ // Return value. Results propagate up the stack.
+ int value = 0;
+
+ // Evaluation environment. Changes propagate
+ // down the stack
+ Env env;
+
+ // Define behavior for each case of the
+ // expression.
+ void visit(Lit &e) override { value = e.value; }
+ void visit(Plus &e) override {
+ e.lhs->accept(*this);
+ auto lhs = value;
+ e.rhs->accept(*this);
+ auto rhs = value;
+ value = lhs + rhs;
+ }
+ void visit(Var &e) override {
+ try {
+ value = env.at(e.name);
+ } catch (std::out_of_range &ex) {
+ throw UnknownVar(e.name);
+ }
+ }
+ void visit(Let &e) override {
+ e.exp->accept(*this);
+ auto orig_env = env;
+ env[e.name] = value;
+ e.body->accept(*this);
+ env = orig_env;
+ }
+};
+
+int main() {
+ // Construct an expression
+ auto x = Plus(std::make_unique(
+ std::string("x"),
+ std::make_unique(3),
+ std::make_unique(
+ std::string("x"))),
+ std::make_unique(2));
+
+ // Construct the evaluator
+ EvalVisitor visitor;
+
+ // Run the evaluator
+ x.accept(visitor);
+
+ // Print the output
+ std::cout << visitor.value << std::endl;
+}
+```
+
+```rust
+use std::collections::HashMap;
+
+// Define expressions.
+//
+// This covers the first 3 sections of the
+// C++ version.
+enum Exp {
+ Var(String),
+ Lit(i32),
+ Plus {
+ lhs: Box,
+ rhs: Box,
+ },
+ Let {
+ var: String,
+ exp: Box,
+ body: Box,
+ },
+}
+
+// Exception for representing expression
+// evaluation errors
+#[derive(Debug)]
+enum EvalError<'a> {
+ UnknownVar(&'a str),
+}
+
+// Define type for evaluation environment
+type Env<'a> = HashMap<&'a str, i32>;
+
+// Define evaluator
+fn eval<'a>(
+ env: &Env<'a>,
+ e: &'a Exp,
+) -> Result> {
+ match e {
+ Exp::Var(x) => env
+ .get(x.as_str())
+ .cloned()
+ .ok_or(EvalError::UnknownVar(x)),
+ Exp::Lit(n) => Ok(*n),
+ Exp::Plus { lhs, rhs } => {
+ let lv = eval(env, lhs)?;
+ let rv = eval(env, rhs)?;
+ Ok(lv + rv)
+ }
+ Exp::Let { var, exp, body } => {
+ let val = eval(env, exp)?;
+ let mut env = env.clone();
+ env.insert(var, val);
+ eval(&env, body)
+ }
+ }
+}
+
+fn main() {
+ use Exp::*;
+
+ // Construct an expression
+ let e = Let {
+ var: "x".to_string(),
+ exp: Box::new(Lit(3)),
+ body: Box::new(Plus {
+ lhs: Box::new(Var("x".to_string())),
+ rhs: Box::new(Lit(2)),
+ }),
+ };
+
+ // Run the evaluator
+ let res = eval(&HashMap::new(), &e);
+
+ // Print the output
+ println!("{:?}", res);
+}
+```
+
+
+
+## Visitors
+
+If the visitor pattern is still needed for some reason, it can be implemented
+similarly to how it is in C++. This can make direct ports of programs that use
+the visitor pattern more feasible. However, the enum-based implementation should
+still be preferred.
+
+The following example shows how to implement the same program as in the previous
+example, but using a visitor in Rust. The C++ program is identical to the
+previous one.
+
+The example also demonstrates using double dispatch with trait objects in Rust.
+The expressions are represented as `dyn Exp` trait objects which accept a `dyn
+Visitor` trait object, and then call on the visitor the method specific to the
+type of expression.
+
+
+
+```cpp
+#include
+#include
+#include
+#include
+#include
+
+// Declare types that visitor can visit
+class Lit;
+class Plus;
+class Var;
+class Let;
+
+// Define abstract class for visitor
+struct Visitor {
+ virtual void visit(Lit &e) = 0;
+ virtual void visit(Plus &e) = 0;
+ virtual void visit(Var &e) = 0;
+ virtual void visit(Let &e) = 0;
+ virtual ~Visitor() = default;
+
+protected:
+ Visitor() = default;
+};
+
+// Define abstract class for expressions
+struct Exp {
+ virtual void accept(Visitor &v) = 0;
+ virtual ~Exp() = default;
+};
+
+// Implement each expression variant
+struct Lit : public Exp {
+ int value;
+
+ Lit(int value) : value(value) {}
+
+ void accept(Visitor &v) override {
+ v.visit(*this);
+ }
+};
+
+struct Plus : public Exp {
+ std::unique_ptr lhs;
+ std::unique_ptr rhs;
+
+ Plus(std::unique_ptr lhs,
+ std::unique_ptr rhs)
+ : lhs(std::move(lhs)), rhs(std::move(rhs)) {
+ }
+
+ void accept(Visitor &v) override {
+ v.visit(*this);
+ }
+};
+
+struct Var : public Exp {
+ std::string name;
+
+ Var(std::string name) : name(name) {}
+
+ void accept(Visitor &v) override {
+ v.visit(*this);
+ }
+};
+
+struct Let : public Exp {
+ std::string name;
+ std::unique_ptr exp;
+ std::unique_ptr body;
+
+ Let(std::string name, std::unique_ptr exp,
+ std::unique_ptr body)
+ : name(std::move(name)),
+ exp(std::move(exp)),
+ body(std::move(body)) {}
+
+ void accept(Visitor &v) override {
+ v.visit(*this);
+ }
+};
+
+// Define Visitor for evaluating expressions
+
+// Exception for representing expression
+// evaluation errors
+struct UnknownVar : std::exception {
+ std::string name;
+
+ UnknownVar(std::string name) : name(name) {}
+
+ const char *what() const noexcept override {
+ return "Unknown variable";
+ }
+};
+
+// Define type for evaluation environment
+using Env = std::unordered_map;
+
+// Define evaluator
+struct EvalVisitor : public Visitor {
+ // Return value. Results propagate up the stack.
+ int value = 0;
+
+ // Evaluation environment. Changes propagate
+ // down the stack
+ Env env;
+
+ // Define behavior for each case of the
+ // expression.
+ void visit(Lit &e) override { value = e.value; }
+ void visit(Plus &e) override {
+ e.lhs->accept(*this);
+ auto lhs = value;
+ e.rhs->accept(*this);
+ auto rhs = value;
+ value = lhs + rhs;
+ }
+ void visit(Var &e) override {
+ try {
+ value = env.at(e.name);
+ } catch (std::out_of_range &ex) {
+ throw UnknownVar(e.name);
+ }
+ }
+ void visit(Let &e) override {
+ e.exp->accept(*this);
+ auto orig_env = env;
+ env[e.name] = value;
+ e.body->accept(*this);
+ env = orig_env;
+ }
+};
+
+int main() {
+ // Construct an expression
+ auto x = Plus(std::make_unique(
+ std::string("x"),
+ std::make_unique(3),
+ std::make_unique(
+ std::string("x"))),
+ std::make_unique(2));
+
+ // Construct the evaluator
+ EvalVisitor visitor;
+
+ // Run the evaluator
+ x.accept(visitor);
+
+ // Print the output
+ std::cout << visitor.value << std::endl;
+}
+```
+
+```rust
+// This is NOT an idiomatic translation. The
+// previous example using Rust enums is.
+
+use std::collections::HashMap;
+
+// Define types that the visitor can visit
+struct Lit(i32);
+struct Plus {
+ lhs: Box,
+ rhs: Box,
+}
+struct Var(String);
+struct Let {
+ name: String,
+ exp: Box,
+ body: Box,
+}
+
+// Define trait for expressions
+trait Exp {
+ // Much like C++ can't have virtual template
+ // methods, Rust can't have trait objects
+ // where the traits have generic methods.
+ //
+ // Therefore the visitor either has to be
+ // mutable to collect the results or the
+ // accept method has to be specialized to a
+ // specific return type.
+ fn accept<'a>(&'a self, v: &mut dyn Visitor<'a>);
+}
+
+// Define trait for the visitor
+trait Visitor<'a> {
+ fn visit_lit(&mut self, e: &'a Lit);
+ fn visit_plus(&mut self, e: &'a Plus);
+ fn visit_var(&mut self, e: &'a Var);
+ fn visit_let(&mut self, e: &'a Let);
+}
+
+// Implement accept behavior for each expression variant
+impl Exp for Lit {
+ fn accept<'a>(&'a self, v: &mut (dyn Visitor<'a>)) {
+ v.visit_lit(self);
+ }
+}
+
+impl Exp for Plus {
+ fn accept<'a>(&'a self, v: &mut dyn Visitor<'a>) {
+ v.visit_plus(self);
+ }
+}
+
+impl Exp for Var {
+ fn accept<'a>(&'a self, v: &mut dyn Visitor<'a>) {
+ v.visit_var(self);
+ }
+}
+
+impl Exp for Let {
+ fn accept<'a>(&'a self, v: &mut dyn Visitor<'a>) {
+ v.visit_let(self);
+ }
+}
+
+// Define Visitor for evaluating expressions
+
+// Error for representing expression evaluation
+// errors.
+//
+// Has a lifetime parameter beacause it borrows
+// the name from the expression.
+#[derive(Debug)]
+enum EvalError<'a> {
+ UnknownVar(&'a str),
+}
+
+// Define type for evaluation environment
+//
+// Has a lifetime parameter because it borrows
+// the names from the expression.
+type Env<'a> = HashMap<&'a str, i32>;
+
+// Define the evaluator
+struct EvalVisitor<'a> {
+ // Return value. Results propagate up the stack.
+ env: Env<'a>,
+
+ // Evaluation environment. Changes propagate
+ // down the stack
+ value: Result>,
+}
+
+// Define behavior for each case of the
+// expression.
+impl<'a> Visitor<'a> for EvalVisitor<'a> {
+ fn visit_lit(&mut self, e: &'a Lit) {
+ self.value = Ok(e.0);
+ }
+
+ fn visit_plus(&mut self, e: &'a Plus) {
+ e.lhs.accept(self);
+ let Ok(lv) = self.value else {
+ return;
+ };
+ e.rhs.accept(self);
+ let Ok(rv) = self.value else {
+ return;
+ };
+ self.value = Ok(lv + rv);
+ }
+
+ fn visit_var(&mut self, e: &'a Var) {
+ self.value = self
+ .env
+ .get(e.0.as_str())
+ .ok_or(EvalError::UnknownVar(&e.0))
+ .copied();
+ }
+
+ fn visit_let(&mut self, e: &'a Let) {
+ e.exp.accept(self);
+ let Ok(val) = self.value else {
+ return;
+ };
+ let orig_env = self.env.clone();
+ self.env.insert(e.name.as_ref(), val);
+ e.body.accept(self);
+ self.env = orig_env;
+ }
+}
+
+fn main() {
+ // Construct an expression
+ let x = Plus {
+ lhs: Box::new(Let {
+ name: "x".to_string(),
+ exp: Box::new(Lit(3)),
+ body: Box::new(Var("x".to_string())),
+ }),
+ rhs: Box::new(Lit(2)),
+ };
+
+ // Construct the evaluator
+ let mut visitor = EvalVisitor {
+ value: Ok(0),
+ env: HashMap::new(),
+ };
+
+ // Run the evaluator
+ x.accept(&mut visitor);
+
+ // Print the output
+ println!("{:?}", visitor.value);
+}
+```
+
+
+
+## Varying data and behavior
+
+In C++, extensions to the visitor pattern are sometimes used to handle
+situations where both data and behavior and vary. However, those solutions also
+make use of dynamic casting. In Rust, that requires opting into
+[RTTI](./../idioms/rtti.md) by making `Any` a supertrait of the trait for the
+visitors, so they can be downcast. While this extension to the visitor pattern
+is possible to implement, the ergonomics of the approach make other approaches
+more common in Rust.
+
+One of the alternative approaches, adopted from functional programming and
+leveraging the design of traits and generics in Rust, is called ["data types à
+la
+carte"](https://www.cambridge.org/core/services/aop-cambridge-core/content/view/14416CB20C4637164EA9F77097909409/S0956796808006758a.pdf/data-types-a-la-carte.pdf).
+
+The following example shows a variation on the earlier examples using this
+pattern to make it so that two parts of the expression type can be defined
+separately and given evaluators separately. This approach can lead to
+performance problems (in large part due to the indirection through nested
+structures) or increases in compilation time, so its necessity should be
+carefully evaluated before it is used.
+
+```rust
+use std::collections::HashMap;
+
+// A type for combining separately-defined
+// expressions. Defining individual expressions
+// completely separately and then using an
+// application-specific sum type instead of nesting
+// Sum can improve performance.
+enum Sum {
+ Inl(L),
+ Inr(R),
+}
+
+// Define arithmetic expressions
+enum ArithExp {
+ Lit(i32),
+ Plus { lhs: E, rhs: E },
+}
+
+// Define let bindings and variables
+enum LetExp {
+ Var(String),
+ Let { name: String, exp: E, body: E },
+}
+
+// Combine the expressions
+type Sig = Sum, LetExp>;
+
+// Define the fixed-point for recursive
+// expressions.
+struct Exp(Sig>);
+
+// Define an evaluator
+
+// The evaluation environment
+type Env<'a> = HashMap<&'a str, i32>;
+
+// Evaluation errors
+#[derive(Debug)]
+enum EvalError<'a> {
+ UndefinedVar(&'a str),
+}
+
+// A trait for expressions that can
+// be evaluated.
+trait Eval {
+ fn eval<'a>(&'a self, env: &Env<'a>) -> Result>;
+}
+
+// Implement the evaluator trait for
+// the administrative types
+
+impl Eval for Sum {
+ fn eval<'a>(&'a self, env: &Env<'a>) -> Result> {
+ match self {
+ Sum::Inl(left) => left.eval(env),
+ Sum::Inr(right) => right.eval(env),
+ }
+ }
+}
+
+impl Eval for Box {
+ fn eval<'a>(&'a self, env: &Env<'a>) -> Result> {
+ self.as_ref().eval(env)
+ }
+}
+
+// Implement the trait for the desired variants.
+impl Eval for ArithExp {
+ fn eval<'a>(&'a self, env: &Env<'a>) -> Result> {
+ match self {
+ ArithExp::Lit(n) => Ok(*n),
+ ArithExp::Plus { lhs, rhs } => Ok(lhs.eval(env)? + rhs.eval(env)?),
+ }
+ }
+}
+
+impl Eval for LetExp {
+ fn eval<'a>(&'a self, env: &Env<'a>) -> Result> {
+ match self {
+ LetExp::Var(x) => env
+ .get(x.as_str())
+ .copied()
+ .ok_or(EvalError::UndefinedVar(x)),
+ LetExp::Let { name, exp, body } => {
+ let arg = exp.eval(env)?;
+ let mut env = env.clone();
+ env.insert(name, arg);
+ body.eval(&env)
+ }
+ }
+ }
+}
+
+// Since the trait is implemented for everything
+// inside of Exp, it can be implemented for Exp.
+impl Eval for Exp {
+ fn eval<'a>(&'a self, env: &Env<'a>) -> Result> {
+ self.0.eval(env)
+ }
+}
+
+// helpers for constructing expressions
+
+fn lit(n: i32) -> Exp {
+ Exp(Sum::Inl(ArithExp::Lit(n)))
+}
+
+fn plus(lhs: Exp, rhs: Exp) -> Exp {
+ Exp(Sum::Inl(ArithExp::Plus {
+ lhs: Box::new(lhs),
+ rhs: Box::new(rhs),
+ }))
+}
+
+fn var(x: &str) -> Exp {
+ Exp(Sum::Inr(LetExp::Var(x.to_string())))
+}
+
+fn elet(name: &str, val: Exp, body: Exp) -> Exp {
+ Exp(Sum::Inr(LetExp::Let {
+ name: name.to_string(),
+ exp: Box::new(val),
+ body: Box::new(body),
+ }))
+}
+
+fn main() {
+ let e = elet("x", lit(3), plus(var("x"), lit(2)));
+
+ println!("{:?}", e.eval(&HashMap::new()));
+}
+```
+
+One thing worth noting about the above implementation is that no dynamic
+dispatch was required.
+
+{{#quiz visitor.toml}}
diff --git a/src/patterns/visitor.toml b/src/patterns/visitor.toml
new file mode 100644
index 0000000..6bc2f8a
--- /dev/null
+++ b/src/patterns/visitor.toml
@@ -0,0 +1,31 @@
+[[questions]]
+type = "MultipleChoice"
+prompt.prompt = """
+Which are true trade-offs are made when defining free functions over an enum
+instead of using the visitor pattern in Rust?
+"""
+prompt.distractors = [
+"""
+Adding behaviors requires changing the enum definition.
+""",
+"""
+Adding behaviors requires changing existing behaviors.
+""",
+"""
+RTTI is necessary to add new variants.
+"""
+]
+answer.answer = [
+"""
+Adding variants requires changing the enum definition.
+""",
+"""
+Adding variants requires changing existing behaviors.
+"""
+]
+context = """
+The compiler checks for exhasutiveness in handling the cases of a Rust
+enum. This makes it easy to determine where in the code additional logic is
+needed to handle the new variants, making the trade-offs easier to live with.
+"""
+id = "8435b363-2e95-42e7-a518-d5746ffef385"
diff --git a/src/patterns/visitor_pattern.md b/src/patterns/visitor_pattern.md
deleted file mode 100644
index 38c9e7f..0000000
--- a/src/patterns/visitor_pattern.md
+++ /dev/null
@@ -1 +0,0 @@
-# Visitor pattern and double dispatch
diff --git a/src/tooling/build_systems.md b/src/tooling/build_systems.md
deleted file mode 100644
index 20231e2..0000000
--- a/src/tooling/build_systems.md
+++ /dev/null
@@ -1 +0,0 @@
-# Build systems (CMake)