The Story of Rust

Steve Klabnik

Let's talk about Rust

Let's talk about Rust

I'm not going to say more about Rust itself yet. We'll get there!

First, let's talk about why you should care about this story.

Let's talk about stories

Totally not Marx

The history of all hitherto existing Rust is the history of 1.0 shipping struggles.

Epoch Rust

Rust has undergone four epochs so far:

Moving between epochs

It took a long time to figure out how Rust ought to work. - Niko

Empiric Iteration

It's basically a completely different language if you compare by features.

It's basically the exact same language if you compare by goals.

Eight years is a long time.

Empiric Iteration

Rust and Servo are both written in Rust.

"This feature seems cool" -> implement -> try it out

Cool? Keep it.

Not cool? Throw it out!

Empiric Iteration

Rust has lost more features than many languages have in the first place.

Empiric Iteration

Iteration does not mean identity crisis. The 'how' may not be clear, but the goal can be.

Epoch Rust

Rust has undergone four epochs so far:

The Personal Years

I have been writing a compiled, concurrent, safe, systems programming language for the past four and a half years.


We do not know what exactly will come of it.


Many older languages better than new ones. We keep forgetting already-learned lessons.


Technology from the past come to save the future from itself

The Personal Years

fn main() {
    log "hello, world";
}

fn max(int x, int y) -> int {
    if (x > y) {
        ret x;
    } else {
        ret y;
    }
}

The Personal Years

obj counter(int i) {
    fn incr() {
        i += 1;
    }
    fn get() -> int {
        ret i;
    }
}

fn main() {
    auto c = counter(10);
    c.incr();
    log c.get();
}

The Personal Years

obj swap[T](tup(T,T) pair) -> tup(T,T) {
    ret tup(pair._1, pair._0);
}

fn main() {
    auto str_pair = tup("hi", "there");
    auto int_pair = tup(10, 12);
    str_pair = swap[str](str_pair);
    int_pair = swap[int](int_pair);
}

The Personal Years

The semantics is the interesting part. The syntax is, really, about the last concern.

The Personal Years

The Personal Years

The Personal Years

The Graydon Years

Rust now a Mozilla project, with Graydon as a BDFL-style figure.

Steady rate of improvement and change.

The team slowly grows.

The Typesystem Years

As the team grows, the typesystem grows as well.

As the typesystem grows, more and more moves from the language to the libraries.

Graydon steps down from the project.

The Typesystem Years

Case study: Channels

rec(task task, chan[T] chan)

task and chan are keywords that the language knows about.

The Typesystem Years

Case study: Channels

use std::thread::Thread;
use std::sync::mpsc::{Sender,Receiver};

struct Foo<T> {
    thread: Thread,
    chan: (Sender<T>, Receiver<T>),
}

The Typesystem Years

Case study: Pointers

let x = @5; // GC'd pointer
let y = ~5; // unique pointer
let z = &5; // borrowed pointer

The Typesystem Years

Case study: Pointers

let y = Box::new(5); // box
let z = &5; // reference

The Typesystem Years

Not typesystem related: Cargo and Crates.io

$ cargo new foo --bin
$ cd foo
$ cargo run
   Compiling foo v0.0.1 (file:///home/steve/tmp/foo)
     Running `target/foo`
Hello, world!

The Typesystem Years

Not typesystem related: Cargo and Crates.io

$ cargo build -v
   Compiling foo v0.0.1 (file:///home/steve/tmp/foo)
     Running `rustc src/main.rs --crate-name foo --crate-type bin -g --out-dir /home/steve/tmp/foo/target --emit=dep-info,link -L dependency=/home/steve/tmp/foo/target -L dependency=/home/steve/tmp/foo/target/deps`

Enable common patterns:

$ cargo build --release -v
   Compiling foo v0.0.1 (file:///home/steve/tmp/foo)
     Running `rustc src/main.rs --crate-name foo --crate-type bin -C opt-level=3 --cfg ndebug --out-dir /home/steve/tmp/foo/target/release --emit=dep-info,link -L dependency=/home/steve/tmp/foo/target/release -L dependency=/home/steve/tmp/foo/target/release/deps`

The Typesystem Years

Not typesystem related: Cargo and Crates.io

$ cat Cargo.toml 
[package]

name = "foo"
version = "0.0.1"
authors = ["Steve Klabnik <steve@steveklabnik.com>"]

The Typesystem Years

Not typesystem related: Cargo and Crates.io

$ cat Cargo.toml 
[package]

name = "foo"
version = "0.0.1"
authors = ["Steve Klabnik <steve@steveklabnik.com>"]

[dependencies]
time = "*"
log = "0.2.1"
$ cargo build
    Updating registry `https://github.com/rust-lang/crates.io-index`
   Compiling log v0.2.1
   Compiling libc v0.1.1
   Compiling gcc v0.1.7
   Compiling time v0.1.15
   Compiling foo v0.0.1 (file:///home/steve/tmp/foo)

The Typesystem Years

As Rust's community grows, three large camps form:

In some ways, Rust is a combination of all three of these things.

The Typesystem Years

March 2014: RFC process begins

Intermezzo: Rust today: Ownership

v = []

v.push("Hello")

x = v[0]

v.push("world")

puts x

Intermezzo: Rust today: Ownership

#include<iostream>
#include<vector>
#include<string>

int main() {
    std::vector<std::string> v;

    v.push_back("Hello");

    std::string& x = v[0];

    v.push_back("world");

    std::cout << x;
}

Intermezzo: Rust today: Ownership

$ g++ hello.cpp -Wall -Werror
$ ./a.out
Segmentation fault (core dumped)

Intermezzo: Rust today: Ownership

If the new size() is greater than capacity() then all iterators and references (including the past-the-end iterator) are invalidated.

Intermezzo: Rust today: Ownership

fn main() {
    let mut v = vec![];

    v.push("Hello");

    let x = &v[0];

    v.push("world");

    println!("{}", x);
}

Intermezzo: Rust today: Ownership

$ cargo run
   Compiling hello_world v0.0.1 (file:///Users/you/src/hello_world)
error: cannot borrow `v` as mutable because it is also borrowed as immutable
    v.push("world");
    ^
note: previous borrow of `v` occurs here; the immutable borrow prevents
subsequent moves or mutable borrows of `v` until the borrow ends
    let x = &v[0];
             ^
note: previous borrow ends here
fn main() {
...
}
^
error: aborting due to previous error

Intermezzo: Rust today: Concurrency

use std::thread::Thread;

fn main() {
    let guards: Vec<_> = (0..10).map(|_| {
        Thread::scoped(|| {
            println!("Hello, world!");
        })
    }).collect();
}

Intermezzo: Rust today: Concurrency

use std::thread::Thread;

fn main() {
    let mut numbers = vec![1, 2, 3];

    for i in 0..3 {
        Thread::scoped(move || {
            for j in 0..3 { numbers[j] += 1 }
        });
    }
}

error: capture of moved value: `numbers`

Intermezzo: Rust today: Concurrency

use std::thread::Thread;
use std::sync::{Arc, Mutex};

fn main() {
    let numbers = Arc::new(Mutex::new(vec![1, 2, 3]));

    for i in 0us..3 {
        let number = numbers.clone();

        Thread::scoped(move || {
            let mut array = number.lock().unwrap();

            array[i] += 1;

            println!("numbers[{}] is {}", i, array[i]);
        });
    }
}

The Release Year

Goal: get some Rust into Firefox by the end of 2015.

The Release Year

Continual pushing the boundaries of what's possible.

It's not just about the language, it's about the ecosystem.

It's not just about the language, it's about the tooling.

It's not just about the language, it's about the community.

It's not just about the language, it's about stability.

The Release Year

Ecosystem:

The Release Year

Tooling:

The Release Year

Community:

The Release Year

Stability:

That's it!

I love Rust, and I hope you do too. If you don't, that's totally cool.

What will the future of this story be? We hope you'll join us in writing the next epoch.

Thank you! <3