+
+
+
+
+
+---
+
+# Assigning a type to a variable
+
+```rust
+fn main() {
+ let x: i32 = 20;
+}
+```
+
+- Rust is strongly and strictly typed
+- Variables use type inference, so no need to specify a type
+- We can be explicit in our types (and sometimes have to be)
+
+---
+layout: two-cols
+---
+
+# Integers
+
+| Length | Signed | Unsigned |
+|---------------|---------|----------|
+| 8 bits | `i8` | `u8` |
+| 16 bits | `i16` | `u16` |
+| 32 bits | `i32` | `u32` |
+| 64 bits | `i64` | `u64` |
+| 128 bits | `i128` | `u128` |
+| pointer-sized | `isize` | `usize` |
+
+- Rust prefers explicit integer sizes
+- Use `isize` and `usize` sparingly
+
+::right::
+
+
+
+# Literals
+
+```rust
+fn main() {
+ let x = 42; // decimal as i32
+ let y = 42u64; // decimal as u64
+ let z = 42_000; // underscore separator
+
+ let u = 0xff; // hexadecimal
+ let v = 0o77; // octal
+ let w = 0b0100_1101; // binary
+ let q = b'A'; // byte syntax (stored as u8)
+}
+```
+
+
+
+
+
+---
+
+# Floating points and floating point literals
+
+```rust
+fn main() {
+ let x = 2.0; // f64
+ let y = 1.0f32; // f32
+}
+```
+
+- `f32`: single precision (32-bit) floating point number
+- `f64`: double precision (64-bit) floating point number
+
+
+
+---
+
+# Numerical operations
+
+```rust
+fn main() {
+ let sum = 5 + 10;
+ let difference = 10 - 3;
+ let mult = 2 * 8;
+ let div = 2.4 / 3.5;
+ let int_div = 10 / 3; // 3
+ let remainder = 20 % 3;
+}
+```
+
+
+
+- These expressions do overflow/underflow checking in debug
+- In release builds these expressions are wrapping, for efficiency
+- You cannot mix and match types here, not even between different integer
+types
+
+```rust
+fn main() {
+ let invalid_div = 2.4 / 5; // Error!
+ let invalid_add = 20u32 + 40u64; // Error!
+}
+```
+
+
+
+
+
+---
+
+# Booleans and boolean operations
+
+```rust
+fn main() {
+ let yes: bool = true;
+ let no: bool = false;
+ let not = !no;
+ let and = yes && no;
+ let or = yes || no;
+}
+```
+
+---
+
+# Comparison operators
+
+```rust
+fn main() {
+ let x = 10;
+ let y = 20;
+ x < y; // true
+ x > y; // false
+ x <= y; // true
+ x >= y; // false
+ x == y; // false
+ x != y; // true
+}
+```
+
+Note: as with numerical operators, you cannot compare different integer and
+float types with each other
+
+```rust
+fn main() {
+ 3.0 < 20; // invalid
+ 30u64 > 20i32; // invalid
+}
+```
+
+
+
+---
+
+# Characters
+
+```rust
+fn main() {
+ let c = 'z';
+ let z = 'ℤ';
+ let heart_eyed_cat = '😻';
+}
+```
+
+- A character is a 32-bit unicode scalar value
+- Very much unlike C/C++ where char is 8 bits
+
+
+
+---
+
+# Strings
+```rust
+ // Owned, heap-allocated string *slice*
+ let s1: String = String::new("Hello, 🌍!");
+```
+
+- Rust strings are UTF-8-encoded
+- Unlike C/C++: *Not null-terminated*
+- Cannot be indexed like C strings
+- Actually many types of strings in Rust
+
+
+
+---
+layout: three-slots
+---
+# Tuples
+
+::left::
+
+```rust
+fn main() {
+ let tup: (i32, f32, char) = (1, 2.0, 'a');
+}
+```
+
+- Group multiple values into a single compound type
+- Fixed size
+- Different types per element
+- Create a tuple by writing a comma-separated list of values inside parentheses
+
+::right::
+
+
+
+```rust
+fn main() {
+ let tup = (1, 2.0, 'Z');
+ let (a, b, c) = tup;
+ println!("({}, {}, {})", a, b, c);
+
+ let another_tuple = (true, 42);
+ println!("{}", another_tuple.1);
+}
+```
+
+- Tuples can be destructured to get to their individual values
+- You can also access individual elements using the period operator followed by
+ a zero based index
+
+
+
+
+
+---
+
+# Arrays
+
+```rust
+fn main() {
+ let arr: [i32; 3] = [1, 2, 3];
+ println!("{}", arr[0]);
+ let [a, b, c] = arr;
+ println!("[{}, {}, {}]", a, b, c);
+}
+```
+
+- Also a collection of multiple values, but this time all of the same type
+- Always a fixed length at compile time (similar to tuples)
+- Use square brackets to access an individual value
+- Destructuring as with tuples
+- Rust always checks array bounds when accessing a value in an array
+
+
+
+---
+
+# Control flow
+
+```rust {all|3-10|4-9|8|13-16|18-20|all}
+fn main() {
+ let mut x = 0;
+ loop {
+ if x < 5 {
+ println!("x: {}", x);
+ x += 1;
+ } else {
+ break;
+ }
+ }
+
+ let mut y = 5;
+ while y > 0 {
+ y -= 1;
+ println!("y: {}", x);
+ }
+
+ for i in [1, 2, 3, 4, 5] {
+ println!("i: {}", i);
+ }
+}
+```
+
+
+
+---
+
+# Functions
+
+```rust
+fn add(a: i32, b: i32) -> i32 {
+ a + b
+}
+
+fn returns_nothing() -> () {
+ println!("Nothing to report");
+}
+
+fn also_returns_nothing() {
+ println!("Nothing to report");
+}
+```
+
+- The function boundary must always be explicitly annotated with types
+- Within the function body type inference may be used
+- A function that returns nothing has the return type *unit* (`()`)
+- The function body contains a series of statements optionally ending with an
+expression
+
+
+
+---
+
+# Statements
+- Statements are instructions that perform some action and do not return a value
+- A definition of any kind (function definition etc.)
+- The `let var = expr;` statement
+- Almost everything else is an expression
+
+## Example statements
+```rust
+fn my_fun() {
+ println!("{}", 5);
+}
+```
+
+```rust
+let x = 10;
+```
+
+
+
+```rust
+let x = (let y = 10); // invalid
+```
+
+
+
+
+
+---
+
+# Expressions
+
+- Expressions evaluate to a resulting value
+- Expressions make up most of the Rust code you write
+- Includes all control flow such as `if` and `while`
+- Includes scoping braces (`{` and `}`)
+- An expression can be turned into a statement by adding a semicolon (`;`)
+
+```rust {all|2-5}
+fn main() {
+ let y = {
+ let x = 3;
+ x + 1
+ };
+ println!("{}", y); // 4
+}
+```
+
+---
+
+# Expressions - control flow
+
+- Control flow expressions as a statement do not need to end with a semicolon
+if they return *unit* (`()`)
+- Remember: A block/function can end with an expression, but it needs to have
+the correct type
+
+```rust {all|3-8|10-15}
+fn main() {
+ let y = 11;
+ // if as an expression
+ let x = if y < 10 {
+ 42
+ } else {
+ 24
+ };
+
+ // if as a statement
+ if x == 42 {
+ println!("Foo");
+ } else {
+ println!("Bar");
+ }
+}
+```
+
+---
+
+# Scope
+
+- We just mentioned the scope braces (`{` and `}`)
+- Variable scopes are actually very important for how Rust works
+
+```rust
+fn main() {
+ println!("Hello, {}", name); // invalid: name is not yet defined
+ let name = "world"; // from this point name is in scope
+ println!("Hello, {}", name);
+} // name goes out of scope
+```
+
+---
+
+# Scope
+
+As soon as a scope ends, all variables for that scope can be removed from the
+stack
+
+```rust
+fn main() { // nothing in scope here
+ let i = 10; // i is now in scope
+ if i > 5 {
+ let j = 20; // j is now also in scope
+ println!("i = {}, j = {}", i, j);
+ } // j is no longer in scope, i still remains
+ println!("i = {}", i);
+} // i is no longer in scope
+```
+
+
\ No newline at end of file
diff --git a/slides/A-foundations/closures.md b/slides/A-foundations/closures.md
new file mode 100644
index 00000000..de6ccb30
--- /dev/null
+++ b/slides/A-foundations/closures.md
@@ -0,0 +1,30 @@
+---
+layout: default
+---
+# Intermezzo: Closures
+
+- Closures are anonymous (unnamed) functions
+- they can capture ("close over") values in their scope
+- they are first-class values
+
+```rust
+fn foo() -> impl Fn(i64, i64) -> i64 {
+ z = 42;
+ |x, y| x + y + z
+}
+
+fn bar() -> i64 {
+ // construct the closure
+ let f = foo();
+
+ // evaluate the closure
+ f(1, 2)
+}
+```
+
+- very useful when working with iterators, `Option` and `Result`.
+
+```rust
+let evens: Vec<_> = some_iterator.filter(|x| x % 2 == 0).collect();
+```
+
diff --git a/slides/A-foundations/composite-types.md b/slides/A-foundations/composite-types.md
new file mode 100644
index 00000000..01dbd0a2
--- /dev/null
+++ b/slides/A-foundations/composite-types.md
@@ -0,0 +1,166 @@
+---
+
+# Types redux
+We have previously looked at some of the basic types in the Rust typesystem
+
+- Primitives (integers, floats, booleans, characters)
+- Compounds (tuples, arrays)
+- Most of the types we looked at were `Copy`
+- Borrowing will make more sense when we look at some more ways we can type
+ our data
+
+---
+
+# Structuring data
+Rust has two important ways to structure data
+
+* structs
+* enums
+* ~~unions~~
+
+
+
+---
+
+# Structs
+A struct is similar to a tuple, but this time the combined type gets its own name
+
+```rust
+struct ControlPoint(f64, f64, bool);
+```
+
+
+
+This is an example of a *tuple struct*. You can access the fields in the struct
+the same way as with tuples:
+
+```rust
+fn main() {
+ let cp = ControlPoint(10.5, 12.3, true);
+ println!("{}", cp.0); // prints 10.5
+}
+```
+
+
+
+
+
+---
+
+# Structs
+Much more common though are structs with named fields
+
+```rust
+struct ControlPoint {
+ x: f64,
+ y: f64,
+ enabled: bool,
+}
+```
+
+* We can add a little more purpose to each field
+* No need to keep our indexing up to date when we add or remove a field
+
+
+
+
+```rust {all|2-6|7}
+fn main() {
+ let cp = ControlPoint {
+ x: 10.5,
+ y: 12.3,
+ enabled: true,
+ };
+ println!("{}", cp.x); // prints 10.5
+}
+```
+
+
+
+
+
+---
+
+# Enumerations
+One of the more powerful kinds of types in Rust are enumerations
+
+```rust
+enum IpAddressType {
+ Ipv4,
+ Ipv6,
+}
+```
+
+* An enumeration (listing) of different *variants*
+* Each variant is an alternative value of the enum, you pick a single value to
+ create an instance
+
+
+
+```rust
+fn main() {
+ let ip_type = IpAddressType::Ipv4;
+}
+```
+
+
+
+---
+
+# Enumerations
+Enums get more powerful, because each variant can have associated data with
+it
+
+```rust
+enum IpAddress {
+ Ipv4(u8, u8, u8, u8),
+ Ipv6(u16, u16, u16, u16, u16, u16, u16, u16),
+}
+```
+
+* This way, the associated data and the variant are bound together
+* Impossible to create an ipv6 address while only giving a 32 bits integer
+
+```rust
+fn main() {
+ let ipv4_home = IpAddress::Ipv4(127, 0, 0, 1);
+ let ipv6_home = IpAddress::Ipv6(0, 0, 0, 0, 0, 0, 0, 1);
+}
+```
+
+* Note: an enum always is as large as the largest variant
+
+
+
+
+
+
+
+
diff --git a/slides/A-foundations/impl-blocks.md b/slides/A-foundations/impl-blocks.md
new file mode 100644
index 00000000..ff188092
--- /dev/null
+++ b/slides/A-foundations/impl-blocks.md
@@ -0,0 +1,102 @@
+---
+
+# Intermission: Impl blocks
+In the past few slides we saw a syntax which wasn't explained before:
+
+```rust {3}
+fn main() {
+ let x = Some(42);
+ let unwrapped = x.unwrap();
+ println!("{}", unwrapped);
+}
+```
+
+* The syntax `x.y()` looks similar to how we accessed a field in a struct
+* We can define functions on our types using impl blocks
+* Impl blocks can be defined on any type, not just structs (with some limitations)
+
+---
+
+# Intermission: Impl blocks
+
+```rust {all|6,13|7-12|7|17}
+enum IpAddress {
+ Ipv4(u8, u8, u8, u8),
+ Ipv6(u16, u16, u16, u16, u16, u16, u16, u16),
+}
+
+impl IpAddress {
+ fn as_u32(&self) -> Option {
+ match self {
+ IpAddress::Ipv4(a, b, c, d) => a << 24 + b << 16 + c << 8 + d
+ _ => None,_
+ }
+ }
+}
+
+fn main() {
+ let addr = IpAddress::Ipv4(127, 0, 0, 1);
+ println!("{:?}", addr.as_u32());
+}
+```
+
+
+
+---
+
+# Intermission: Impl blocks, self and Self
+
+- The `self` parameter defines how the method can be used.
+- The `Self` type is a shorthand for the type on which the current
+ implementation is specified.
+
+```rust {all|4-6|8-14|16-18}
+struct Foo(i32);
+
+impl Foo {
+ fn consume(self) -> Self {
+ Self(self.0 + 1)
+ }
+
+ fn borrow(&self) -> &i32 {
+ &self.0
+ }
+
+ fn borrow_mut(&mut self) -> &mut i32 {
+ &mut self.0
+ }
+
+ fn new() -> Self {
+ Self(0)
+ }
+}
+```
+
+---
+
+# Intermission: Impl blocks, the self parameter
+The self parameter is called the *receiver*.
+
+* The self parameter is always the first and it always has the type on which it
+ was defined
+* We never specify the type of the self parameter
+* We can optionally prepend `&` or `&mut ` to self to indicate that we take
+ a value by reference
+* Absence of a self parameter means that the function is an associated function
+ instead
+
+```rust
+fn main () {
+ let mut f = Foo::new();
+ println!("{}", f.borrow());
+ *f.borrow_mut() = 10;
+ let g = f.consume();
+ println!("{}", g.borrow());
+}
+```
diff --git a/slides/A-foundations/interior-mutability.md b/slides/A-foundations/interior-mutability.md
new file mode 100644
index 00000000..e69de29b
diff --git a/slides/A-foundations/layouts b/slides/A-foundations/layouts
new file mode 120000
index 00000000..00799ed8
--- /dev/null
+++ b/slides/A-foundations/layouts
@@ -0,0 +1 @@
+../layouts
\ No newline at end of file
diff --git a/slides/A-foundations/lifetime-annotations.md b/slides/A-foundations/lifetime-annotations.md
new file mode 100644
index 00000000..e69de29b
diff --git a/slides/A-foundations/move-semantics.md b/slides/A-foundations/move-semantics.md
new file mode 100644
index 00000000..6927f17a
--- /dev/null
+++ b/slides/A-foundations/move-semantics.md
@@ -0,0 +1,493 @@
+---
+layout: two-cols
+---
+# Memory management
+
+- Most of what we have seen so far is stack-based and small in size
+- All these primitive types are `Copy`: create a copy on the stack every time
+we need them somewhere else
+- We don't want to pass a copy all the time
+- Large data that we do not want to copy
+- Modifying original data
+- What about data structures with a variable size?
+
+::right::
+
+
+
+![Memory Layout](/images/A1-memory-expanded.svg)
+
+
+
+
+---
+layout: section
+---
+# Rust's ownership model
+
+---
+layout: default
+---
+# Memory
+
+- A computer program consists of a set of instructions
+- Those instructions manipulate some memory
+- How does a program know what memory can be used?
+
+
+
+---
+
+# Fundamentals
+
+There are two mechanisms at play here, generally known as the stack and the heap
+
+
+
+
+
Frame 1
+
Frame 2
+
+
+
Free memory
+
+
+
Heap
+
Allocated
+
+
+
+
+
+
🠔 Stack pointer
+
+
+
+
+
+---
+
+# Fundamentals
+
+There are two mechanisms at play here, generally known as the stack and the heap
+
+
+
+
+
Frame 1
+
Frame 2
+
Frame 3
+
+
+
Free memory
+
+
+
Heap
+
Allocated
+
+
+
+
+
+
🠔 Stack pointer
+
+ A stack frame is allocated for every function call. It contains exactly
+ enough space for all local variables, arguments and stores where the
+ previous stack frame starts.
+
+
+
+
+
+
+---
+
+# Fundamentals
+
+There are two mechanisms at play here, generally known as the stack and the heap
+
+
+
+
+
Frame 1
+
Frame 2
+
+
+
Free memory
+
+
+
Heap
+
Allocated
+
+
+
+
+
+
🠔 Stack pointer
+
+ Once a function call ends we just move back up, and everything below is
+ available as free memory once more.
+
+
+
+
+
+
+---
+
+# Stack limitations
+
+The stack has limitations though, because it only grows as a result of a
+function call.
+
+* Size of items on stack frame must be known at compile time
+* If I don't know the size of a variable up front: What size should my stack
+frame be?
+* How can I handle arbitrary user input efficiently?
+
+
+
+
+
+---
+
+# The Heap
+
+If the lifetime of some data needs to outlive a certain scope, it can not be placed on the stack.
+We need another construct: the heap.
+
+It's all in the name, the heap is just one big pile of memory for you to store
+stuff in. But what part of the heap is in use? What part is available?
+
+* Data comes in all shapes and sizes
+* When a new piece of data comes in we need to find a place in the heap that
+still has a large enough chunk of data available
+* When is a piece of heap memory no longer needed?
+* Where does it start? Where does it end?
+* When can we start using it?
+
+
+
+---
+
+# Variable scoping (recap)
+
+```rust
+fn main() { // nothing in scope here
+ let i = 10; // i is now in scope
+ if i > 5 {
+ let j = i; // j is now also in scope
+ println!("i = {}, j = {}", i, j);
+ } // j is no longer in scope, i still remains
+ println!("i = {}", i);
+} // i is no longer in scope
+```
+
+
+
+* `i` and `j` are examples containing a `Copy` type
+* What if copying is too expensive?
+
+
+
+
+
+---
+layout: four-square
+---
+
+# Ownership
+
+::topleft::
+
+```rust
+let x = 5;
+let y = x;
+println!("{}", x);
+```
+
+::topright::
+
+
+
+::bottomleft::
+
+
+
+```rust
+// Create an owned, heap allocated string
+let s1 = String::from("hello");
+let s2 = s1;
+println!("{}, world!", s1);
+```
+
+
+
+
+
+Strings store their data on the heap because they can grow
+
+
+
+::bottomright::
+
+
+
+
+
+```text
+Compiling playground v0.0.1 (/playground)
+error[E0382]: borrow of moved value: `s1`
+--> src/main.rs:4:28
+ |
+2 | let s1 = String::from("hello");
+ | -- move occurs because `s1` has type `String`, which does not implement the `Copy` trait
+3 | let s2 = s1;
+ | -- value moved here
+4 | println!("{}, world!", s1);
+ | ^^ value borrowed here after move
+```
+
+
+
+
+
+
+
+---
+
+
+
+
+
+
+
+
+
+
+# Ownership
+
+- There is always ever only one owner of a stack value
+- Once the owner goes out of scope (and is removed from the stack), any associated values on the
+ heap will be cleaned up as well
+- Rust transfers ownership for non-copy types: *move semantics*
+
+
+
+---
+
+```rust
+fn main() {
+ let s1 = String::from("hello");
+ let len = calculate_length(s1);
+ println!("The length of '{}' is {}.", s1, len);
+}
+
+fn calculate_length(s: String) -> usize {
+ s.len()
+}
+```
+
+
+
+
+
+```text
+Compiling playground v0.0.1 (/playground)
+error[E0382]: borrow of moved value: `s1`
+--> src/main.rs:4:43
+ |
+2 | let s1 = String::from("hello");
+ | -- move occurs because `s1` has type `String`, which does not implement the `Copy` trait
+3 | let len = calculate_length(s1);
+ | -- value moved here
+4 | println!("The length of '{}' is {}.", s1, len);
+ | ^^ value borrowed here after move
+```
+
+
+
+
+
+
+
+---
+
+# Moving out of a function
+
+We can return a value to move it out of the function
+
+```rust
+fn main() {
+ let s1 = String::from("hello");
+ let (len, s1) = calculate_length(s1);
+ println!("The length of '{}' is {}.", s1, len);
+}
+
+fn calculate_length(s: String) -> (usize, String) {
+ (s.len(), s)
+}
+```
+
+
+
+
+
+```text
+Compiling playground v0.0.1 (/playground)
+Finished dev [unoptimized + debuginfo] target(s) in 5.42s
+Running `target/debug/playground`
+The length of 'hello' is 5.
+```
+
+
+
+
+
+
+
+---
+
+# Clone
+
+
+
+- Many types in Rust are `Clone`-able
+- Use can use clone to create an explicit clone (in contrast to `Copy` which
+ creates an implicit copy).
+- Creating a clone can be expensive and could take a long time, so be careful
+- Not very efficient if a clone is short-lived like in this example
+
+```rust
+fn main() {
+ let x = String::from("hellothisisaverylongstring...");
+ let len = get_length(x.clone());
+ println!("{}: {}", x, len);
+}
+
+fn get_length(arg: String) -> usize {
+ arg.len()
+}
+```
+
+
\ No newline at end of file
diff --git a/slides/A-foundations/optionals-errors.md b/slides/A-foundations/optionals-errors.md
new file mode 100644
index 00000000..56b1b3dd
--- /dev/null
+++ b/slides/A-foundations/optionals-errors.md
@@ -0,0 +1,277 @@
+---
+
+# Option
+A quick look into the basic enums available in the standard library
+
+* Rust does not have null, but you can still define variables that optionally
+ do not have a value
+* For this you can use the `Option` enum
+
+```rust
+enum Option {
+ Some(T),
+ None,
+}
+
+fn main() {
+ let some_int = Option::Some(42);
+ let no_string: Option = Option::None;
+}
+```
+
+
+
+---
+
+# Option
+A quick look into the basic enums available in the standard library
+
+* Rust does not have null, but you can still define variables that optionally
+ do not have a value
+* For this you can use the `Option` enum
+
+```rust
+enum Option {
+ Some(T),
+ None,
+}
+
+fn main() {
+ let some_int = Some(42);
+ let no_string: Option = None;
+}
+```
+
+---
+
+# Error handling
+What would we do when there is an error?
+
+```rust
+fn divide(x: i64, y: i64) -> i64 {
+ if y == 0 {
+ // what to do now?
+ } else {
+ x / y
+ }
+}
+```
+
+---
+
+# Error handling
+What would we do when there is an error?
+
+```rust
+fn divide(x: i64, y: i64) -> i64 {
+ if y == 0 {
+ panic!("Cannot divide by zero");
+ } else {
+ x / y
+ }
+}
+```
+
+* A panic in Rust is the most basic way to handle errors
+* A panic error is an all or nothing kind of error
+* A panic will immediately stop running the current thread/program and instead
+ immediately work to shut it down, using one of two methods:
+ * Unwinding: going up throught the stack and making sure that each value
+ is cleaned up
+ * Aborting: ignore everything and immediately exit the thread/program
+* Only use panic in small programs if normal error handling would also exit
+ the program
+* Avoid using panic in library code or other reusable components
+
+
+
+---
+
+# Error handling
+What would we do when there is an error? We could try and use the option enum
+instead of panicking
+
+```rust
+fn divide(x: i64, y: i64) -> Option {
+ if y == 0 {
+ None
+ } else {
+ Some(x / y)
+ }
+}
+```
+
+---
+
+# Result
+Another really powerful enum is the result, which is even more useful if we
+think about error handling
+
+```rust
+enum Result {
+ Ok(T),
+ Err(E),
+}
+
+enum DivideError {
+ DivisionByZero,
+ CannotDivideOne,
+}
+
+fn divide(x: i64, y: i64) -> Result {
+ if x == 1 {
+ Err(DivideError::CannotDivideOne)
+ } else if y == 0 {
+ Err(DivideError::DivisionByZero)
+ } else {
+ Ok(x / y)
+ }
+}
+```
+
+---
+
+# Handling results
+Now that we have a function that returns a result we have to think about how
+we handle that error at the call-site
+
+```rust
+fn div_zero_fails() {
+ match divide(10, 0) {
+ Ok(div) => println!("{}", div),
+ Err(e) => panic!("Could not divide by zero"),
+ }
+}
+```
+
+* We made the signature of the `divide` function explicit in how it can fail
+* The user of the function can now decide what to do, even if it is panicking
+* Note: just as with `Option` we never have to use `Result::Ok` and
+ `Result::Err` because they have been made available globally
+
+
+
+
+---
+
+# Handling results
+Especially when writing initial prototyping code you will often find yourself
+wanting to write error handling code later, Rust has a useful utility function
+to help you for both `Option` and `Result`:
+
+```rust
+fn div_zero_fails() {
+ let div = divide(10, 0).unwrap();
+ println!("{}", div);
+}
+```
+
+* Unwrap checks if the Result/Option is `Ok(x)` or `Some(x)` respectively and
+ then return that `x`, otherwise it will panic your program with an error
+ message
+* Having unwraps all over the place is generally considered a bad practice
+* Sometimes you can ensure that an error won't occur, in such cases `unwrap`
+ can be a good solution
+
+---
+
+# Handling results
+Especially when writing initial prototyping code you will often find yourself
+wanting to write error handling code later, Rust has a useful utility function
+to help you for both `Option` and `Result`:
+
+```rust
+fn div_zero_fails() {
+ let div = divide(10, 0).unwrap_or(-1);
+ println!("{}", div);
+}
+```
+
+Besides unwrap, there are some other useful utility functions
+
+- `unwrap_or(val)`: If there is an error, use the value given to unwrap_or
+ instead
+- `unwrap_or_default()`: Use the default value for that type if there is an
+ error
+- `expect(msg)`: Same as unwrap, but instead pass a custom error message
+- `unwrap_or_else(fn)`: Same as unwrap_or, but instead call a function that
+ generates a value in case of an error
+
+
+
+---
+
+# Result and the `?` operator
+Results are so common that there is a special operator associated with them, the
+`?` operator
+
+```rust
+fn can_fail() -> Result {
+ let intermediate_result = match divide(10, 0) {
+ Ok(ir) => ir,
+ Err(e) => return Err(e);
+ };
+
+ match divide(intermediate_result, 0) {
+ Ok(sec) => Ok(sec * 2),
+ Err(e) => Err(e),
+ }
+}
+```
+
+
+
+Look how this function changes if we use the `?` operator
+
+```rust
+fn can_fail() -> Result {
+ let intermediate_result = divide(10, 0)?;
+ Ok(divide(intermediate_result, 0)? * 2)
+}
+```
+
+
+
+---
+
+# Result and the `?` operator
+
+```rust
+fn can_fail() -> Result {
+ let intermediate_result = divide(10, 0)?;
+ Ok(divide(intermediate_result, 0)? * 2)
+}
+```
+
+* The `?` operator does an implicit match, if there is an error, that error
+ is then immediately returned and the function returns early
+* If the result is `Ok()` then the value is extracted and we can continue right
+ away
+
diff --git a/slides/A-foundations/ownership-borrowing.md b/slides/A-foundations/ownership-borrowing.md
new file mode 100644
index 00000000..0d40a278
--- /dev/null
+++ b/slides/A-foundations/ownership-borrowing.md
@@ -0,0 +1,292 @@
+---
+
+# Ownership
+We previously talked about ownership
+
+* In Rust there is always a single owner for each stack value
+* Once the owner goes out of scope any associated values should be cleaned up
+* Copy types creates copies, all other types are *moved*
+
+
+
+---
+
+# Moving out of a function
+We have previously seen this example
+
+
+```rust
+fn main() {
+ let s1 = String::from("hello");
+ let len = calculate_length(s1);
+ println!("The length of '{}' is {}.", s1, len);
+}
+fn calculate_length(s: String) -> usize {
+ s.len()
+}
+```
+
+* This does not compile because ownership of `s1` is moved into
+ `calculate_length`, meaning it is no longer available in `main` afterwards
+* We can use `Clone` to create an explicit copy
+* We can give ownership back by returning the value
+* What about other options?
+
+---
+
+# Borrowing
+- We can make an analogy with real life: if somebody owns something you can
+ borrow it from them, but eventually you have to give it back
+- If a value is borrowed, it is not moved and the ownership stays with the
+ original owner
+- To borrow in Rust, we create a *reference*
+
+```rust {all|3|7|all}
+fn main() {
+ let x = String::from("hello");
+ let len = get_length(&x);
+ println!("{}: {}", x, len);
+}
+
+fn get_length(arg: &String) -> usize {
+ arg.len()
+}
+```
+
+---
+
+# References (immutable)
+
+```rust
+fn main() {
+ let s = String::from("hello");
+ change(&s);
+ println!("{}", s);
+}
+
+fn change(some_string: &String) {
+ some_string.push_str(", world");
+}
+```
+
+
+
+
+
+```text
+ Compiling playground v0.0.1 (/playground)
+error[E0596]: cannot borrow `*some_string` as mutable, as it is behind a `&` reference
+ --> src/main.rs:8:5
+ |
+7 | fn change(some_string: &String) {
+ | ------- help: consider changing this to be a mutable reference: `&mut String`
+8 | some_string.push_str(", world");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `some_string` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+
+For more information about this error, try `rustc --explain E0596`.
+error: could not compile `playground` due to previous error
+```
+
+
+
+```text
+ Compiling playground v0.0.1 (/playground)
+ Finished dev [unoptimized + debuginfo] target(s) in 2.55s
+ Running `target/debug/playground`
+hello, world
+```
+
+
+
+
+
+
+
+- A mutable reference can even fully replace the original value
+- To do this, you can use the dereference operator (`*`) to modify the value:
+
+```rust
+*some_string = String::from("Goodbye");
+```
+
+
+
+
+
+---
+
+
+# Rules for borrowing and references
+
+- You may only ever have one mutable reference at the same time
+- You may have any number of immutable references at the same time as long as
+ there is no mutable reference
+- References cannot *live* longer than their owners
+- A reference will always at all times point to a valid value
+
+These rules are enforced by the Rust compiler.
+
+
+
+---
+
+# Borrowing and memory safety
+Combined with the ownership model we can be sure that whole classes of errors
+cannot occur.
+
+* Rust is memory safe without having to use any runtime background process such
+ as a garbage collector
+* But we still get the performance of a language that would normally let you
+ manage memory manually
+
+
+
+---
+
+# Reference example
+
+```rust
+fn main() {
+ let mut s = String::from("hello");
+ let s1 = &s;
+ let s2 = &s;
+ let s3 = &mut s;
+ println!("{} - {} - {}", s1, s2, s3);
+}
+```
+
+
+
+
+
+```text
+ Compiling playground v0.0.1 (/playground)
+error[E0502]: cannot borrow `s` as mutable because it is also borrowed as immutable
+ --> src/main.rs:5:14
+ |
+3 | let s1 = &s;
+ | -- immutable borrow occurs here
+4 | let s2 = &s;
+5 | let s3 = &mut s;
+ | ^^^^^^ mutable borrow occurs here
+6 | println!("{} - {} - {}", s1, s2, s3);
+ | -- immutable borrow later used here
+
+For more information about this error, try `rustc --explain E0502`.
+error: could not compile `playground` due to previous error
+```
+
+
+
+
+
+---
+
+# Returning references
+
+You can return references, but the value borrowed from must exist at least as
+long
+
+```rust
+fn give_me_a_ref() -> &String {
+ let s = String::from("Hello, world!");
+ &s
+}
+```
+
+
+
+
+
+```md {8}
+ Compiling playground v0.0.1 (/playground)
+error[E0106]: missing lifetime specifier
+ --> src/lib.rs:1:23
+ |
+1 | fn give_me_a_ref() -> &String {
+ | ^ expected named lifetime parameter
+ |
+ = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
+help: consider using the `'static` lifetime
+ |
+1 | fn give_me_a_ref() -> &'static String {
+ | ~~~~~~~~
+
+For more information about this error, try `rustc --explain E0106`.
+error: could not compile `playground` due to previous error
+```
+
+
+
+
+
+---
+
+# Returning references
+
+You can return references, but the value borrowed from must exist at least as
+long
+
+```rust
+fn give_me_a_ref(input: &(String, i32)) -> &String {
+ &input.0
+}
+```
+
+
+
+```rust
+fn give_me_a_value() -> String {
+ let s = String::from("Hello, world!");
+ s
+}
+```
+
+
diff --git a/slides/A-foundations/pattern-matching.md b/slides/A-foundations/pattern-matching.md
new file mode 100644
index 00000000..434669a9
--- /dev/null
+++ b/slides/A-foundations/pattern-matching.md
@@ -0,0 +1,100 @@
+---
+
+# Pattern matching
+To extract data from enums we can use pattern matching using the
+`if let [pattern] = [value]` statement
+
+```rust
+fn accept_ipv4(ip: IpAddress) {
+ if let IpAddress::Ipv4(a, b, _, _) = ip {
+ println!("Accepted, first octet is {} and second is {}", a, b);
+ }
+}
+```
+
+* `a` and `b` introduce local variables within the body of the if that contain
+ the values of those fields
+* The underscore (`_`) can be used to accept any value
+
+---
+
+# Match
+Pattern matching is very powerful if combined with the match statement
+
+```rust
+fn accept_home(ip: IpAddress) {
+ match ip {
+ IpAddress::Ipv4(127, 0, 0, 1) => {
+ println!("You are home!");
+ },
+ IpAddress::Ipv6(0, 0, 0, 0, 0, 0, 0, 1) => {
+ println!("You are in your new home!");
+ },
+ _ => {
+ println!("You are not home");
+ },
+ }
+}
+```
+
+* Every part of the match is called an arm
+* A match is exhaustive, which means that all values must be handled by one of
+ the match arms
+* You can use a catch-all `_` arm to catch any remaining cases if there are any
+ left
+
+---
+
+# Match as an expression
+The match statement can even be used as an expression
+
+```rust
+fn get_first_byte(ip: IpAddress) {
+ let first_byte = match ip {
+ IpAddress::Ipv4(a, _, _, _) => a,
+ IpAddress::Ipv6(a, _, _, _, _, _, _, _) => a / 256 as u8,
+ };
+ println!("The first byte was: {}", first_byte);
+}
+```
+
+* The match arms can return a value, but their types have to match
+* Note how here we do not need a catch all `_` arm because all cases have
+ already been handled by the two arms
+
+---
+
+# Generics
+Structs become even more powerful if we introduce a little of generics
+
+```rust
+struct PointFloat(f64, f64);
+struct PointInt(i64, i64);
+```
+
+We are repeating ourselves here, what if we could write a data structure for
+both of these cases?
+
+
+
+```rust
+struct Point(T, T);
+
+fn main() {
+ let float_point: Point = Point(10.0, 10.0);
+ let int_point: Point = Point(10, 10);
+}
+```
+
+Generics are much more powerful, but this is all we need for now
+
+
+
+
diff --git a/slides/A-foundations/slices.md b/slides/A-foundations/slices.md
new file mode 100644
index 00000000..ee32e3af
--- /dev/null
+++ b/slides/A-foundations/slices.md
@@ -0,0 +1,361 @@
+---
+
+# Vectors and arrays
+What if we wanted to write a sum function, we could define one for arrays of
+a specific size:
+
+```rust
+fn sum(data: &[i64; 10]) -> i64 {
+ let mut total = 0;
+ for val in data {
+ total += val;
+ }
+ total
+}
+```
+
+---
+
+# Vectors and arrays
+Or one for just vectors:
+
+```rust
+fn sum(data: &Vec) -> i64 {
+ let mut total = 0;
+ for val in data {
+ total += val;
+ }
+ total
+}
+```
+
+---
+
+# Slices
+What if we want something to work on arrays of any size? Or what if we want
+to support summing up only parts of a vector?
+
+* A slice is a dynamically sized view into a contiguous sequence
+* Contiguous: elements are layed out in memory such that they are evenly spaced
+* Dynamically sized: the size of the slice is not stored in the type, but is
+ determined at runtime
+* View: a slice is never an owned data structure
+* Slices are typed as `[T]`, where `T` is the type of the elements in the slice
+
+---
+
+# Slices
+
+```rust
+fn sum(data: [i64]) -> i64 {
+ let mut total = 0;
+ for val in data {
+ total += val;
+ }
+ total
+}
+
+fn main() {
+ let data = vec![10, 11, 12, 13, 14];
+ println!("{}", sum(data));
+}
+```
+
+
+
+```text
+ Compiling playground v0.0.1 (/playground)
+error[E0277]: the size for values of type `[i64]` cannot be known at compilation time
+ --> src/main.rs:1:8
+ |
+1 | fn sum(data: [i64]) -> i64 {
+ | ^^^^ doesn't have a size known at compile-time
+ |
+ = help: the trait `Sized` is not implemented for `[i64]`
+help: function arguments must have a statically known size, borrowed types always have a known size
+```
+
+
+
+
+
+---
+
+# Slices
+
+```rust
+fn sum(data: &[i64]) -> i64 {
+ let mut total = 0;
+ for val in data {
+ total += val;
+ }
+ total
+}
+
+fn main() {
+ let data = vec![10, 11, 12, 13, 14];
+ println!("{}", sum(&data));
+}
+```
+
+
+
+```text
+ Compiling playground v0.0.1 (/playground)
+ Finished dev [unoptimized + debuginfo] target(s) in 0.89s
+ Running `target/debug/playground`
+60
+```
+
+
+
+---
+
+# Slices
+
+* `[T]` is an incomplete type: we need to know how many `T` there are
+* Types that have a known compile time size implement the `Sized` trait, raw
+ slices do **not** implement it
+* Slices must always be behind a reference type, i.e. `&[T]` and `&mut [T]`
+ (but also `Box<[T]>` etc)
+* The length of the slice is always stored together with the reference
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+---
+
+# Creating slices
+Because we cannot create slices out of thin air, they have to be located
+somewhere. There are three possible ways to create slices:
+
+* Using a borrow
+ - We can borrow from arrays and vectors to create a slice of their entire
+ contents
+* Using ranges
+ - We can use ranges to create a slice from parts of a vector or array
+* Using a literal (for immutable slices only)
+ - We can have memory statically available from our compiled binary
+
+---
+
+# Creating slices
+Using a borrow
+
+```rust
+fn sum(data: &[i32]) -> i32 { /* ... */ }
+
+fn main() {
+ let v = vec![1, 2, 3, 4, 5, 6];
+ let total = sum(&v);
+ println!("{}", total);
+}
+```
+
+---
+
+# Creating slices
+Using ranges
+
+```rust
+fn sum(data: &[i32]) -> i32 { /* ... */ }
+
+fn main() {
+ let v = vec![0, 1, 2, 3, 4, 5, 6];
+ let all = sum(&v[..]);
+ let except_first = sum(&v[1..]);
+ let except_last = sum(&v[..5]);
+ let except_ends = sum(&v[1..5]);
+}
+```
+
+* The range `start..end` contains all values `x` with `start <= x < end`.
+
+
+
+* Note: you can also use ranges on their own, for example in a for loop:
+
+```rust
+fn main() {
+ for i in 0..10 {
+ println!("{}", i);
+ }
+}
+```
+
+
+
+---
+
+# Creating slices
+From a literal
+
+```rust {3-5,12|7-9,13|all}
+fn sum(data: &[i32]) -> i32 { /* ... */ }
+
+fn get_v_arr() -> &'static [i32] {
+ &[0, 1, 2, 3, 4, 5, 6]
+}
+
+fn get_v_vec() -> &'static [i32] {
+ &vec![0, 1, 2, 3, 4, 5, 6]
+}
+
+fn main() {
+ let all = sum(get_v_arr());
+ let all_vec = sum(get_v_vec());
+}
+```
+
+
+
+* Interestingly `get_v_arr` works, even though the literal looks like it would
+ only exist temporarily
+* Literals actually exist during the entire lifetime of the program
+* `&'static` here is used to indicate that this slice will exist the entire
+ lifetime of the program
+
+
+---
+
+# Strings
+We have already seen the `String` type being used before, but let's dive a
+little deeper
+
+* Strings are used to represent text
+* In Rust they are always valid UTF-8
+* Their data is stored on the heap
+* A String is almost the same as `Vec` with extra checks to prevent
+ creating invalid text
+
+
+---
+
+# Strings
+Let's take a look at some strings
+
+```rust
+fn main() {
+ let s = String::from("Hello world\nSee you!");
+ println!("{:?}", s.split_once(" "));
+ println!("{}", s.len());
+ println!("{:?}", s.starts_with("Hello"));
+ println!("{}", s.to_uppercase());
+ for line in s.lines() {
+ println!("{}", line);
+ }
+}
+```
+
+---
+
+# String literals
+We have already seen string literals being used while constructing a string.
+The string literal is what arrays are to vectors
+
+```rust
+fn main() {
+ let s1 = "Hello world";
+ let s2 = String::from("Hello world");
+}
+```
+
+---
+
+# String literals
+We have already seen string literals being used while constructing a string.
+The string literal is what arrays are to vectors
+
+```rust
+fn main() {
+ let s1: &'static str = "Hello world";
+ let s2: String = String::from("Hello world");
+}
+```
+
+* `s1` is actually a slice, a string slice
+
+---
+
+# String literals
+We have already seen string literals being used while constructing a string.
+The string literal is what arrays are to vectors
+
+```rust
+fn main() {
+ let s1: &str = "Hello world";
+ let s2: String = String::from("Hello world");
+}
+```
+
+* `s1` is actually a slice, a string slice
+
+---
+
+# str - the string slice
+It should be possible to have a reference to part of a string. But what is it?
+
+* Not `[u8]`: not every sequence of bytes is valid UTF-8
+* Not `[char]`: we could not create a slice from a string since it is stored as
+ UTF-8 encoded bytes
+* We introduce a new special kind of slice: `str`
+* For string slices we do not use brackets!
+
+---
+
+# str, String, array, Vec
+
+| Static | Dynamic | Borrowed |
+|----------|----------|----------|
+| `[T; N]` | `Vec` | `&[T]` |
+| - | `String` | `&str` |
+
+* There is no static variant of str
+* This would only be useful if we wanted strings of an exact length
+* But just like we had the static slice literals, we can use `&'static str`
+ literals for that instead!
+
+---
+
+# String or str
+When do we use String and when do we use str?
+
+```rust
+fn string_len(data: &String) -> usize {
+ data.len()
+}
+```
+
+---
+
+# String or str
+When do we use String and when do we use str?
+
+```rust
+fn string_len(data: &str) -> usize {
+ data.len()
+}
+```
+
+* Prefer `&str` over `String` whenever possible
+* If you need to mutate a string you might try `&mut str`, but you cannot
+ change a slice's length
+* Use `String` or `&mut String` if you need to fully mutate the string
diff --git a/slides/A-foundations/smart-pointers.md b/slides/A-foundations/smart-pointers.md
new file mode 100644
index 00000000..2767530d
--- /dev/null
+++ b/slides/A-foundations/smart-pointers.md
@@ -0,0 +1,41 @@
+---
+
+# Boxing
+There are several reasons to box a variable on the heap
+
+* When something is too large to move around
+* We need something that is sized dynamically
+* For writing recursive data structures
+
+```rust
+struct Node {
+ data: Vec,
+ parent: Node,
+}
+```
+
+---
+
+# Boxing
+There are several reasons to box a variable on the heap
+
+* When something is too large to move around
+* We need something that is sized dynamically
+* For writing recursive data structures
+
+```rust
+struct Node {
+ data: Vec,
+ parent: Box,
+}
+```
+
+
diff --git a/slides/A-foundations/trait-objects.md b/slides/A-foundations/trait-objects.md
new file mode 100644
index 00000000..eb9c8a2c
--- /dev/null
+++ b/slides/A-foundations/trait-objects.md
@@ -0,0 +1,338 @@
+---
+layout: section
+---
+# Trait objects & dynamic dispatch
+
+---
+layout: default
+---
+
+# Trait... Object?
+- We learned about traits in module A3
+- We learned about generics and `monomorphization`
+
+There's more to this story though...
+
+*Question: What was monomorphization again?*
+
+---
+layout: default
+---
+
+# Monomorphization: recap
+
+```rust
+impl MyAdd for i32 {/* - snip - */}
+impl MyAdd for f32 {/* - snip - */}
+
+fn add_values(left: &T, right: &T) -> T
+{
+ left.my_add(right)
+}
+
+fn main() {
+ let sum_one = add_values(&6, &8);
+ assert_eq!(sum_one, 14);
+ let sum_two = add_values(&6.5, &7.5);
+ println!("Sum two: {}", sum_two); // 14
+}
+```
+
+Code is monomorphized:
+ - Two versions of `add_values` end up in binary
+ - Optimized separately and very fast to run (static dispatch)
+ - Slow to compile and larger binary
+
+---
+layout: default
+---
+
+# Dynamic dispatch
+*What if don't know the concrete type implementing the trait at compile time?*
+
+```rust{all|1-8|10-12|14-23|17-20}
+use std::io::Write;
+use std::path::PathBuf;
+
+struct FileLogger { log_path: PathBuf }
+impl Write for FileLogger { /* - snip -*/}
+
+struct StdOutLogger;
+impl Write for StdOutLogger { /* - snip -*/}
+
+fn log(entry: &str, logger: &mut L) {
+ write!(logger, "{}", entry);
+}
+
+fn main() {
+ let log_file: Option =
+ todo!("read args");
+ let mut logger = match log_file {
+ Some(log_path) => FileLogger { log_path },
+ Nome => StdOutLogger,
+ };
+
+ log("Hello, world!🦀", &mut logger);
+}
+```
+
+---
+layout: default
+---
+# Error!
+
+
+```txt
+error[E0308]: `match` arms have incompatible types
+ --> src/main.rs:19:17
+ |
+17 | let mut logger = match log_file {
+ | ______________________-
+18 | | Some(log_path) => FileLogger { log_path },
+ | | ----------------------- this is found to be of type `FileLogger`
+19 | | Nome => StdOutLogger,
+ | | ^^^^^^^^^^^^ expected struct `FileLogger`, found struct `StdOutLogger`
+20 | | };
+ | |_____- `match` arms have incompatible types
+```
+
+*What's the type of `logger`?*
+
+---
+layout: default
+---
+
+# Heterogeneous collections
+*What if we want to create collections of different types implementing the same trait?*
+
+```rust{all|1-13|15-21}
+trait Render {
+ fn paint(&self);
+}
+
+struct Circle;
+impl Render for Circle {
+ fn paint(&self) { /* - snip - */ }
+}
+
+struct Rectangle;
+impl Render for Rectangle {
+ fn paint(&self) { /* - snip - */ }
+}
+
+fn main() {
+ let mut shapes = Vec::new();
+ let circle = Circle;
+ shapes.push(circle);
+ let rect = Rectangle;
+ shapes.push(rect);
+ shapes.iter().for_each(|shape| shape.paint());
+}
+```
+
+---
+layout: default
+---
+
+# Error again!
+```txt
+ Compiling playground v0.0.1 (/playground)
+error[E0308]: mismatched types
+ --> src/main.rs:20:17
+ |
+20 | shapes.push(rect);
+ | ---- ^^^^ expected struct `Circle`, found struct `Rectangle`
+ | |
+ | arguments to this method are incorrect
+ |
+note: associated function defined here
+ --> /rustc/2c8cc343237b8f7d5a3c3703e3a87f2eb2c54a74/library/alloc/src/vec/mod.rs:1836:12
+
+For more information about this error, try `rustc --explain E0308`.
+error: could not compile `playground` due to previous error
+```
+
+*What is the type of `shapes`?*
+
+---
+layout: default
+---
+# Trait objects to the rescue
+
+- Opaque type that implements a set of traits
+- Type description: `dyn T: !Sized` where `T` is a `trait`
+- Like slices, Trait Objects always live behind pointers (`&dyn T`, `&mut dyn T`, `Box`, `...`)
+- Concrete underlying types are erased from trait object
+
+```rust{all|5-7}
+fn main() {
+ let log_file: Option =
+ todo!("read args");
+ // Create a trait object that implements `Write`
+ let logger: &mut dyn Write = match log_file {
+ Some(log_path) => &mut FileLogger { log_path },
+ Nome => &mut StdOutLogger,
+ };
+}
+```
+---
+layout: two-cols
+---
+
+# Layout of trait objects
+
+```rust
+/// Same code as last slide
+fn main() {
+ let log_file: Option =
+ todo!("read args");
+ // Create a trait object that implements `Write`
+ let logger: &mut dyn Write = match log_file {
+ Some(log_path) => &mut FileLogger { log_path },
+ Nome => &mut StdOutLogger,
+ };
+
+ log("Hello, world!🦀", &mut logger);
+}
+```
+
+
+- *💸 Cost: pointer indirection via vtable → less performant*
+- *💰 Benefit: no monomorphization → smaller binary & shorter compile time!*
+
+
+::right::
+
+
+
+
+---
+layout: default
+---
+
+# Fixing dynamic logger
+
+- Trait objects `&dyn T`, `Box`, ... implement `T`!
+
+```rust{all|9-12|1-2}
+// We no longer require L be `Sized`, so to accept trait objects
+fn log(entry: &str, logger: &mut L) {
+ write!(logger, "{}", entry);
+}
+
+fn main() {
+ let log_file: Option =
+ todo!("read args");
+ // Create a trait object that implements `Write`
+ let logger: &mut dyn Write = match log_file {
+ Some(log_path) => &mut FileLogger { log_path },
+ Nome => &mut StdOutLogger,
+ };
+
+ log("Hello, world!🦀", logger);
+}
+```
+And all is well!
+
+---
+layout: default
+---
+
+# Forcing dynamic dispatch
+
+Sometimes you want to enforce API users (or colleagues) to use dynamic dispatch
+
+```rust{all|1}
+fn log(entry: &str, logger: &mut dyn Write) {
+ write!(logger, "{}", entry);
+}
+
+fn main() {
+ let log_file: Option =
+ todo!("read args");
+ // Create a trait object that implements `Write`
+ let logger: &mut dyn Write = match log_file {
+ Some(log_path) => &mut FileLogger { log_path },
+ Nome => &mut StdOutLogger,
+ };
+
+
+ log("Hello, world!🦀", &mut logger);
+}
+```
+
+---
+layout: default
+---
+
+# Fixing the renderer
+
+```rust
+fn main() {
+ let mut shapes = Vec::new();
+ let circle = Circle;
+ shapes.push(circle);
+ let rect = Rectangle;
+ shapes.push(rect);
+ shapes.iter().for_each(|shape| shape.paint());
+}
+```
+
+Becomes
+
+```rust{all|2,3,5}
+fn main() {
+ let mut shapes: Vec> = Vec::new();
+ let circle = Box::new(Circle);
+ shapes.push(circle);
+ let rect = Box::new(Rectangle);
+ shapes.push(rect);
+ shapes.iter().for_each(|shape| shape.paint());
+}
+```
+
+All set!
+
+
+---
+layout: default
+---
+
+# Trait object limitations
+
+- Pointer indirection cost
+- Harder to debug
+- Type erasure
+- Not all traits work:
+
+*Traits need to be 'Object Safe'*
+
+
+---
+layout: default
+---
+
+# Object safety
+
+In order for a trait to be object safe, these conditions need to be met:
+
+- If `trait T: Y`, then`Y` must be object safe
+- trait `T` must not be `Sized`: *Why?*
+- No associated constants allowed*
+- No associated types with generic allowed*
+- All associated functions must either be dispatchable from a trait object, or explicitly non-dispatchable
+ - e.g. function must have a receiver with a reference to `Self`
+
+Details in [The Rust Reference](https://doc.rust-lang.org/reference/items/traits.html#object-safety). Read them!
+
+*These seem to be compiler limitations
+
+---
+layout: default
+---
+
+# So far...
+
+- Trait objects allow for dynamic dispatch and heterogeneous
+- Trait objects introduce pointer indirection
+- Traits need to be object safe to make trait objects out of them
\ No newline at end of file
diff --git a/slides/A-foundations/traits-generics.md b/slides/A-foundations/traits-generics.md
new file mode 100644
index 00000000..8bb1709e
--- /dev/null
+++ b/slides/A-foundations/traits-generics.md
@@ -0,0 +1,336 @@
+---
+layout: section
+---
+# Introduction to generics
+
+---
+layout: default
+---
+# The problem
+
+```rust
+fn add_u32(l: u32, r: u32) -> u32 { /* -snip- */ }
+
+fn add_i32(l: i32, r: i32) -> i32 { /* -snip- */ }
+
+fn add_f32(l: f32, r: f32) -> f32 { /* -snip- */ }
+
+/* ... */
+```
+
+
+
+
+Or, in plain English:
+
+- `` = "let `T` be a type"
+- `lhs: T` "let `lhs` be of type `T`"
+- `-> T` "let `T` be the return type of this function"
+
+
+
+
+
+Some open points:
+
+- What can we do with a `T`?
+- What should the body be?
+
+
+
+---
+layout: default
+---
+# Bounds on generic code
+
+
+We need to provide information to the compiler:
+- Tell Rust what `T` can do
+- Tell Rust what `T` is accepted
+- Tell Rust how `T` implements functionality
+
+---
+layout: default
+---
+
+# `trait`
+
+
+Describe what the type can do
+```rust
+trait MyAdd {
+ fn my_add(&self, other: &Self) -> Self;
+}
+```
+
+---
+layout: default
+---
+# `impl trait`
+
+
+Describe how the type does it
+
+```rust{all|1|2-8}
+impl MyAdd for u32 {
+ fn my_add(&self, other: &Self) -> Self {
+ *self + *other
+ }
+}
+```
+
+---
+layout: default
+---
+# Using a `trait`
+
+```rust{all|1-2|5-6|7-9|10-12}
+// Import the trait
+use my_mod::MyAdd
+
+fn main() {
+ let left: u32 = 6;
+ let right: u32 = 8;
+ // Call trait method
+ let result = left.my_add(&right);
+ assert_eq!(result, 14);
+ // Explicit call
+ let result = MyAdd::my_add(&left, &right);
+ assert_eq!(result, 14);
+}
+```
+
+- Trait needs to be in scope
+- Call just like a method
+- Or by using the explicit associated function syntax
+
+---
+layout: default
+---
+# Trait bounds
+
+```rust{all|1-3,5|5,7-11}
+fn add_values(this: &T, other: &T) -> T {
+ this.my_add(other)
+}
+
+// Or, equivalently
+
+fn add_values(this: &T, other: &T) -> T
+ where T: MyAdd
+{
+ this.my_add(other)
+}
+```
+
+Now we've got a *useful* generic function!
+
+English: *"For all types `T` that implement the `MyAdd` `trait`, we define..."*
+
+---
+layout: default
+---
+# Limitations of `MyAdd`
+What happens if...
+
+- We want to add two values of different types?
+- Addition yields a different type?
+
+---
+layout: default
+---
+
+# Making `MyAdd` itself generic
+
+
+Add an 'Input type' `O`:
+
+```rust{all|1-3|5-9}
+trait MyAdd {
+ fn my_add(&self, other: &O) -> Self;
+}
+
+impl MyAdd for u32 {
+ fn my_add(&self, other: &u16) -> Self {
+ *self + (*other as u32)
+ }
+}
+```
+
+We can now add a `u16` to a `u32`.
+
+---
+layout: default
+---
+
+# Defining output of `MyAdd`
+
+- Addition of two given types always yields in one specific type of output
+- Add *associated type* for addition output
+
+```rust{all|2-3|7-9|6-20}
+trait MyAdd {
+ type Output;
+ fn my_add(&self, other: &O) -> Self::Output;
+}
+
+impl MyAdd for u32 {
+ type Output = u64;
+
+ fn my_add(&self, other: &u16) -> Self::Output {
+ *self as u64 + (*other as u64)
+ }
+}
+
+impl MyAdd for u32 {
+ type Output = u32;
+
+ fn my_add(&self, other: &u32) -> Self::Output {
+ *self + *other
+ }
+}
+```
+
+---
+layout: default
+---
+# `std::ops::Add`
+The way `std` does it
+
+```rust{all|1|2-4}
+pub trait Add {
+ type Output;
+
+ fn add(self, rhs: Rhs) -> Self::Output;
+}
+```
+
+- Default type of `Self` for `Rhs`
+
+---
+layout: default
+---
+# `impl std::ops::Add`
+
+```rust
+use std::ops::Add;
+pub struct BigNumber(u64);
+
+impl Add for BigNumber {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self::Output {
+ BigNumber(self.0 + rhs.0)
+ }
+}
+
+fn main() {
+ // Call `Add::add`
+ let res = BigNumber(1).add(BigNumber(2));
+}
+```
+
+What's the type of `res`?
+
+---
+layout: default
+---
+# `impl std::ops::Add` (2)
+
+```rust
+pub struct BigNumber(u64);
+
+impl std::ops::Add for BigNumber {
+ type Output = u128;
+
+ fn add(self, rhs: Self) -> Self::Output {
+ (self.0 as u128) + (rhs as u128)
+ }
+}
+
+fn main() {
+ let res = BigNumber(1) + 3u32;
+}
+```
+
+What's the type of `res`?
+
+---
+layout: default
+---
+# Traits: Type Parameter vs. Associated Type
+
+### Type parameter (input type)
+*if trait can be implemented for many combinations of types*
+```rust
+// We can add both a u32 value and a u32 reference to a u32
+impl Add for u32 {/* */}
+impl Add<&u32> for u32 {/* */}
+```
+
+### Associated type (output type)
+*to define a type for a single implementation*
+```rust
+impl Add for u32 {
+ // Addition of two u32's is always u32
+ type Output = u32;
+}
+```
+
+---
+layout: default
+---
+
+# `#[derive]` a `trait`
+
+```rust
+#[derive(Clone)]
+struct Dolly {
+ num_legs: u32,
+}
+
+fn main() {
+ let dolly = Dolly { num_legs: 4 };
+ let second_dolly = dolly.clone();
+ assert_eq!(dolly.num_legs, second_dolly.num_legs);
+}
+```
+
+- Some traits are trivial to implement
+- Derive to quickly implement a trait
+- For `Clone`: derived `impl` calls `clone` on each field
+
+---
+layout: default
+---
+# Orphan rule
+
+*Coherence: There must be **at most one** implementation of a trait for any given type*
+
+Trait can be implemented for a type **iff**:
+- Either your crate defines the trait
+- Or your crate defines the type
+
+Or both, of course
diff --git a/slides/A-foundations/vec.md b/slides/A-foundations/vec.md
new file mode 100644
index 00000000..74d92611
--- /dev/null
+++ b/slides/A-foundations/vec.md
@@ -0,0 +1,87 @@
+---
+
+# Vec: storing more of the same
+The vector is an array that can grow
+
+* Compare this to the array we previously saw, which has a fixed size
+
+```rust
+fn main() {
+ let arr = [1, 2];
+ println!("{:?}", arr);
+
+ let mut nums = Vec::new();
+ nums.push(1);
+ nums.push(2);
+ println!("{:?}", nums);
+}
+```
+
+---
+
+# Vec
+Vec is such a common type that there is an easy way to initialize
+it with values that looks similar to arrays
+
+```rust
+fn main() {
+ let mut nums = vec![1, 2];
+ nums.push(3);
+ println!("{:?}", nums);
+}
+```
+
+---
+
+# Vec: memory layout
+How can a vector grow? Things on the stack need to be of a fixed size
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+---
+
+# Put it in a box
+That pointer from the stack to the heap, how do we create such a thing?
+
+* Boxing something is the way to store a value on the heap
+* A `Box` uniquely owns that value, there is no one else that also owns that same
+ value
+* Even if the type inside the box is `Copy`, the box itself is not, move
+ semantics apply to a box.
+
+```rust
+fn main() {
+ // put an integer on the heap
+ let boxed_int = Box::new(10);
+}
+```
+