Typing is not just OOP

Types:

Types:

fn parse(s: Stream)
    -> Result<Ast, ParseError>
{
    unimplemented!();
}

result errors

pub enum Result<T, E> {
    Ok(T),
    Err(E),
}
return Ok(Ast { ... })
return Err(ParseError::new())

enums generics

enum ParseError {
    Io(io::Error),
    UnexpectedCharacter,
    IntError { cause: ParseIntError,
               position: Pos },
}

enums errors error-hierarchy

match err {
    Io(io) => connection.close(),
    UnexpectedCharacter
    => println!("bad char"),
}

match non-exhaustive

error[E0004]: non-exhaustive patterns: `IntError { .. }` not covered
  --> src/main.rs:14:11
   |
6  | / enum ParseError {
7  | |     Io(io::Error),
8  | |     UnexpectedCharacter,
9  | |     IntError { cause: ParseIntError,
   | |     -------- not covered
10 | |                position: Pos },
11 | | }
   | |_- `ParseError` defined here
...
14 |       match err {
   |             ^^^ pattern `IntError { .. }` not covered
   |
   = help: ensure that all possible cases are being handled,
           possibly by adding wildcards or more match arms

rustc-error

match err {
    Io(io) => connection.close(),
    UnexpectedCharacter
    => println!("bad char"),
    IntError { cause, .. }
    => println!("bad int: {}", cause),
}

match structural-match unused-fields

let (new_state, action) = match (msg, state) {
    (Ping, Leader { .. })       =>  // re-elect
    (Ping, _)                   =>  // follow
    (Pong, me @ Leader { .. })  =>  // count
    (Pong, _)                   =>  // re-elect
    (Vote(id), Starting { .. }) =>  // vote
    (Vote(id),
     Electing {epoch, mut votes_for_me,
               deadline, needed_votes}) =>  // check
    (Vote(_), me @ Voted { .. })
    | (Vote(_), me @ Leader { .. })
    | (Vote(_), me @ Follower { .. }) =>  // discard
};
let Config {
    host: a_host, port: a_port,
    listen_queue: _,
} = a;
let Config {
    host: b_host, port: b_port, ..
} = b;
return a_host == b_host && a_port == b_port;

unpacking exhaustiveness pattern-matching

#[non_exhaustive]
enum ParseError {
    Io(io::Error),
    UnexpectedCharacter,
    IntError { cause: ParseIntError,
               position: Pos },
}

forward-compatibility semver

match err {
    Io(io) => connection.close(),
    _ => println!("error: {}", err),
}

non-exhaustive catch-all

enum ParseError {
    Io(io::Error),
    Lexer(Box<dyn Error>),
    Parser(Box<dyn Error>),
}

errors dynamic exhaustive boxing efficiency

pub struct ParserError {
    internal: InternalError,
}
enum InternalError {
    Io(...),
    Lexer(...),
}

visibility forward-compatibility semver

pub struct ParserError(InternalError);
pub(crate) enum InternalError {
    Io(...),
    Lexer(...),
}

new-type visibility

pub struct UpstreamName(Arc<str>);
pub struct DownstreamName(Arc<str>);
struct Server {
    up: Map<UpstreamName, Upstream>,
    down: Map<DownstreamName, Downstream>,
}

new-type arc interning validation

#[derive(Clone)]
pub struct Percentile(u16);
impl TryFrom for Percentile {...}
impl Into for Percentile {...}
fn get(perc: Percentile) -> Value {
    return self.percentiles[perc.0];
}

new-type validation performance ints conversion

pub struct Token { level: u8, slot: u32 }
fn create_timeout() -> Token { }
fn clear_timeout(tok: Token) { }

new-type token-pattern single-use linear-types

let (tx, rx) = channel::oneshot();
thread::spawn(move || {
    rx.send(1);
});

single-use linear-types move threading

error[E0382]: use of moved value: `tx`
  --> src/main.rs:23:9
   |
22 |         tx.send(1);
   |         -- value moved here
23 |         tx.send(2);
   |         ^^ value used here after move
   |
   = note: move occurs because `tx` has type `Sender`,
           which does not implement the `Copy` trait

linear-types move rustc-error

for (&key, _) in &map {
    if key.start_with("x") {
        map.remove(&key);
    }
}

borrow-checker ownership

error[E0502]: cannot borrow `m` as mutable because \
              it is also borrowed as immutable
 --> src/main.rs:7:13
  |
5 |     for (&key, _) in &map {
  |                       ---
  |                       |
  |                       immutable borrow occurs here
  |                       immutable borrow later used here
6 |         if key.starts_with("x") {
7 |             map.remove(&key);
  |             ^^^^^^^^^^^^^^^^ mutable borrow occurs here

borrow-checker rustc-error

for (&key, _) in &map {
    if key.start_with("x") {
        map.remove(&key);
        break;
    }
}

borrow-checker ownership nll

let x = HashMap::new();
x.insert("key1", v1);
x.insert("key2", v2);
let shared = Arc::new(x);
thread1_channel.send(shared.clone());
thread2_channel.send(shared.clone());

mutability shared-state

let shared = Arc::new(Mutex::new(x));
thread::spawn(move || {
    let x: MutexGuard<HashMap<_, _>>;
    x = shared.lock()
    x.insert("x");
})

mutability shared-mutable-state raii lifetime

let gil = Python::acquire_gil();
let py = gil.python();
let dic1 = PyDict::new(py);
dic1.set_item(py,
    "key1", PyInt::new(py, 1000))?;

python token-pattern lifetime

let a = HashMap::new();
a.insert("x", 1);
let b = HashMap::new();
b.insert("key1", a);  # a is moved
# a.insert()  -- is error
b.get_mut("key1").insert("y", 2);

recursive-mutability

let a = TcpStream::connect("localhost:1234");
a.write(b"test");
a.read(&mut buf);

sharing sockets

let mut a = BufStream::new(
    TcpStream::connect("localhost:1234"));
a.write(text);
a.write(b"\n");
a.read_line(&mut buf);

sharing buffering mutation

let a = BufStream::new(
    TcpSocket::connect("localhost:1234"));
let (mut tx, mut rx) = a.split();
thread::spawn(move || {
    # rx.write()  -- no such method
    rx.read_line(&mut buf);
})
tx.write(text);
tx.write(b"\n");

sharing buffering mutation

Inherent mutability

Rust-style mutability

Shared Mutable State

Conclusion