# 06: No null -- Option and Result as the absence/failure story. # # Exercises: generic sum types from the prelude, `` instantiation, # early return, `?` propagation, `if let`-style destructuring. # These live in the prelude but are ordinary Dodo definitions: # # type Option = None | Some(T) # type Result = Ok(T) | Err(E) const TABLE_SIZE: Uint8 = 16 type Entry = { key: Uint8, value: Uint16 } type LookupError = | NotFound | TableCorrupt fn find(table: [Entry; 16], key: Uint8) -> Option { for entry in table { if entry.key == key { # `return` for early exit; the final expression of a # block is otherwise its value, ML-style. return Some(entry.value) } } None } fn lookup(table: [Entry; 16], key: Uint8) -> Result { # `match` bridging Option to Result. A `.ok_or(...)` prelude # helper would collapse this; undecided whether methods on # prelude types are day-one. match find(table, key) { Some(value) => Ok(value), None => Err(NotFound), } } fn lookup_pair( table: [Entry; 16], a: Uint8, b: Uint8, ) -> Result { # `?` unwraps Ok or early-returns the Err, exactly as in Rust. # Cheap to compile (a branch), huge ergonomic win with no-null. let first = lookup(table, a)? let second = lookup(table, b)? Ok(first + second) } fn main() { var table: [Entry; 16] = [Entry { key: 0, value: 0 }; 16] table[3] = Entry { key: 7, value: 1000 } # `if let` for one-armed matches. if let Some(value) = find(table, 7) { # (use value) let _ = value } loop {} }