Rust for your brain/team/justice.

Clint Byrum -- @SpamapS on Freenode IRC and Twitter. http://fewbar.com/

Cloud Software Engineer, GoDaddy
Words are my own I do not speak for GoDaddy, Mozilla, or the Rust project.
Programming Language Rant

Systems Languages

  • C and pointers were a revolution - Finally a HIGH level language
  • C++ -- HIGH level in that you need to be HIGH to appreciate it
  • C# -- Oh clever another horizontal line -- and foreach
  • C++11 -- Oh yeah we can have foreach too, but we still call it for.
  • ObjectiveC -- All your user base are belong to iPhone.

Systems Languages

Every single C descendent puts memory safety on the user.

Enter Memory Safe Languages

Java*, Perl, PHP, Python, Ruby, node.js -- All do GC and take memory control away from programmer.
*java still has pointers but doesn't do arthmetic on them

GC languages can struggle with concurrency

  • Java VM pauses threads to GC objects.
  • Python, Ruby, etc. have Global Interpreter Lock when executing Python code

Shiny New Systems Languages

  • Go - Compiled duck-typed and syntax sugar for concurrency. Runs inside Go runtime with GC to avoid memory management.
  • Rust - Compiled, strong-typed with generics. Explicit scoped memory management and object lifetimes expressed in language.

Why not Go?

It's a great language, and easier to learn. But it only goes halfway into systems programming success, where Rust can give you as much control as C, and has the added bonus of Generics

Rust For your Brain
Explicit Mutability and borrow rules reduce need for unit tests
Strong typing also means not having to unit test as much.
Trait system gives some of the dynamic language flexibility back

                        use std::fmt;

                        struct Bus {
                            name: &'static str,
                        }

                        struct Train {
                            line: &'static str,
                        }

                        struct Plane {
                            callsign: &'static str,
                        }

                        impl fmt::Display for Bus {
                            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                                write!(f, "{} bus", self.name)
                            }
                        }
                        impl fmt::Display for Train {
                            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                                write!(f, "{} train", self.line)
                            }
                        }
                        impl fmt::Display for Plane {
                            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                                write!(f, "{} flight", self.callsign)
                            }
                        }

                        fn main() {
                            let b1 = Bus { name: "LAX Flyaway" };
                            let t1 = Train { line: "Pacific Coastliner"};
                            let p1 = Plane { callsign: "El Mariachi"};

                            println!("I took the {} to the {} and then hopped on the {}.", b1, t1, p1); 
                        }
                      

No easier in Python


class Bus(object):
    def __init__(self, name):
       self.name = name 

    def __str__(self):
        return "%s bus" % (self.name,)

class Train(object):
    def __init__(self, line):
       self.line = line 

    def __str__(self):
        return "%s train" % (self.line,)

class Plane(object):
    def __init__(self, callsign):
       self.callsign = callsign 

    def __str__(self):
        return "%s plane" % (self.callsign,)

b1 = Bus("LAX Flyaway")
t1 = Train("Pacific Coastliner")
p1 = Plane("El Mariachi")

print("I took the {} to the {} and then hopped on the {}.".format(b1, t1, p1))
                      

"Fearless Concurrency" -- Go ahead and make a thread, we dare you

  • Explicit mutability makes it easy to find global mutation
  • Built in Send/Sync traits for objects allow compile time identification of thread safe objects
  • Deadlock detection is still NP-complete. -- Hooray we get to keep our jobs
You can opt out of these safeguards when you need to.

use std::cell::RefCell;
use std::thread;

let result = thread::spawn(move || {
   let c = RefCell::new(5);
   let m = c.borrow_mut();

   let b = c.borrow(); // this causes a panic
}).join();

assert!(result.is_err());
                      
Opt-in to garbage collection when you need flexible data ownership.

use std::rc::Rc;

struct Owner {
    name: String,
    // ...other fields
}

struct Gadget {
    id: i32,
    owner: Rc,
    // ...other fields
}

fn main() {
    // Create a reference-counted `Owner`.
    let gadget_owner: Rc = Rc::new(
        Owner {
            name: "Gadget Man".to_string(),
        }
    );

    // Create `Gadget`s belonging to `gadget_owner`. Cloning the `Rc`
    // value gives us a new pointer to the same `Owner` value, incrementing
    // the reference count in the process.
    let gadget1 = Gadget {
        id: 1,
        owner: Rc::clone(&gadget_owner),
    };
    let gadget2 = Gadget {
        id: 2,
        owner: Rc::clone(&gadget_owner),
    };

    // Dispose of our local variable `gadget_owner`.
    drop(gadget_owner);

    // Despite dropping `gadget_owner`, we're still able to print out the name
    // of the `Owner` of the `Gadget`s. This is because we've only dropped a
    // single `Rc`, not the `Owner` it points to. As long as there are
    // other `Rc` values pointing at the same `Owner`, it will remain
    // allocated. The field projection `gadget1.owner.name` works because
    // `Rc` automatically dereferences to `Owner`.
    println!("Gadget {} owned by {}", gadget1.id, gadget1.owner.name);
    println!("Gadget {} owned by {}", gadget2.id, gadget2.owner.name);

    // At the end of the function, `gadget1` and `gadget2` are destroyed, and
    // with them the last counted references to our `Owner`. Gadget Man now
    // gets destroyed as well.
}
                      
Rust For Your Team

For your dev team...

Programming languages aren't just for computers.

Having explicit mutability and reference lifetimes helps be clear to humans too.


                    important = dict()  # Will this change? When? What goes in it?
                    

                    use std::collections::HashMap;

                    let mut important: HashMap = HashMap::new();
                    
English/Chinese/Spanish/Hindi/etc. are all terrible at representing abstract concepts succinctly and clearly. Say it with code!

For your ops team...

Finding bugs at compile time means throwing better stuff over the wall to ops*.



   Compiling borrowing v0.1.0 (file:///Users/cbyrum/src/SpamapS/presentation/borrowing)
error[E0505]: cannot move out of `pyth` because it is borrowed
  --> src/main.rs:20:30
   |
20 |     users.insert(&pyth.name, pyth);
   |                   ---------  ^^^^ move out of `pyth` occurs here
   |                   |
   |                   borrow of `pyth.name` occurs here

error[E0505]: cannot move out of `kant` because it is borrowed
  --> src/main.rs:21:30
   |
21 |     users.insert(&kant.name, kant);
   |                   ---------  ^^^^ move out of `kant` occurs here
   |                   |
   |                   borrow of `kant.name` occurs here

error: aborting due to 2 previous errors

error: Could not compile `borrowing`.

To learn more, run the command again with --verbose.
                    

For your Dev & Ops...

  • How things get built and deploy matters. Ruby/Perl/Python packaging can be a nightmare.
  • C/C++ have layers on layers of dependency hell even after existing for 30 years.

New langs, better package/build/deploy stories.

  • Go has nice tie-ins with git and builds static binaries
  • Rust's "Cargo" tool is extremely well thought out and well integrated with crates.io for easy code re-use.
https://crates.io/

For your Dev & Ops....

Who is eating up all my RAM?

For your Dev & Ops....

Nodepool? Call nodepool team. Zuul? Call zuul team. Wait.. JAVA?! ALWAYS JAVA

For your Dev & Ops....

Runtimes matter
Rust For Justice
Firefox is aimed at freedom and privacy, and its authors, Mozilla.org, invented Rust. Firefox Quantum

This Is Unix Rust, I KNOW THIS

  • HTML Rendering engine rewritten in Rust -- "Servo"
  • CSS Rendering engine rewritten in Rust to be parallelized
  • Released in November -- super legit

Why would they do that?

  • Firefox's original C++-bound memory model is basically why Google Chrome/Chromium exists.
  • Rust authors experimented with the idea that less garbage collection and memory tied more concretely to scope would beat the Process memory model in the long run
THANK YOU

Clint Byrum -- @SpamapS on Freenode IRC and Twitter. http://fewbar.com/