Steve Klabnik
Rust is a programming language.
It's been in development a long time.
It's been one year since 1.0.
I'm here to tell you about that.
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.
This is a story about history
History can be divided up into 'epochs'
Epochs are determined by the predominant paradigm of the time
As things change, the paradigm (and hence the epoch) changes
Rust has undergone four epochs so far:
The Personal Years (2006-2010)
The Graydon Years (2010-2012)
The Typesystem Years (2012-2014)
The Release Year (2015 -> May 2016)
We are now entering a new epoch: The Production Year (May 2016 -> ?)
It took a long time to figure out how Rust ought to work. - Niko
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.
Rust and Servo are both written in Rust.
"This feature seems cool" -> implement -> try it out
Cool? Keep it.
Not cool? Throw it out!
Rust has lost more features than many languages have in the first place.
Iteration does not mean identity crisis. The 'how' may not be clear, but the goal can be.
Rust has undergone four epochs so far:
The Personal Years (2006-2010)
The Graydon Years (2010-2012)
The Typesystem Years (2012-2014)
The Release Year (2015)
We are now entering a new epoch: The Production Year (May 2016 -> ?)
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
fn main() { log "hello, world"; }
fn max(int x, int y) -> int { if (x > y) { ret x; } else { ret y; } }
obj counter(int i) { fn incr() { i += 1; } fn get() -> int { ret i; } } fn main() { auto c = counter(10); c.incr(); log c.get(); }
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 semantics is the interesting part. The syntax is, really, about the last concern.
Rust now a Mozilla project, with Graydon as a BDFL-style figure.
Steady rate of improvement and change.
The team slowly grows.
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.
Case study: Channels
rec(task task, chan[T] chan)
task
and chan
are keywords that the language knows about.
Case study: Channels
use std::thread::Thread; use std::sync::mpsc::{Sender,Receiver}; struct Foo<T> { thread: Thread, chan: (Sender<T>, Receiver<T>), }
Case study: Pointers
let x = @5; // GC'd pointer let y = ~5; // unique pointer let z = &5; // borrowed pointer
Case study: Pointers
let y = Box::new(5); // box let z = &5; // reference
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!
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`
Not typesystem related: Cargo and Crates.io
$ cat Cargo.toml
[package]
name = "foo"
version = "0.0.1"
authors = ["Steve Klabnik <steve@steveklabnik.com>"]
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)
As Rust's community grows, three large camps form:
In some ways, Rust is a combination of all three of these things.
March 2014: RFC process begins
v = []
v.push("Hello")
x = v[0]
v.push("world")
puts x
#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;
}
$ g++ hello.cpp -Wall -Werror
$ ./a.out
Segmentation fault (core dumped)
If the new size() is greater than capacity() then all iterators and references (including the past-the-end iterator) are invalidated.
fn main() { let mut v = vec![]; v.push("Hello"); let x = &v[0]; v.push("world"); println!("{}", x); }
$ 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
use std::thread; fn main() { let guards: Vec<_> = (0..10).map(|_| { thread::spawn(|| { println!("Hello, world!"); }) }).collect(); }
use std::thread; fn main() { let guards: Vec<_> = (0..10).map(|_| { thread::spawn(|| { println!("Hello, world!"); }) }).collect(); }
error: capture of moved value: `numbers`
use std::thread::Thread; use std::sync::{Arc, Mutex}; fn main() { let numbers = Arc::new(Mutex::new(vec![1, 2, 3])); let mut handles = Vec::new(); for i in 0..3 { let number = numbers.clone(); let handle = thread::spawn(move || { let mut array = number.lock().unwrap(); array[i] += 1; println!("numbers[{}] is {}", i, array[i]); }); handles.push(handle); } for handle in handles { handle.join().unwrap(); } }
extern crate crossbeam; fn main() { let numbers = [1, 2, 3]; crossbeam::scope(|scope| { for i in &mut numbers { scope.spawn(move || { numbers[i] += 1; println!("numbers[{}] is {}", i, numbers[i]); }); } }); }
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 stability.
It's not just about the language, it's about the community.
Ecosystem:
rustc
Tooling:
Makefile
again.rustfmt
: coming soonrustfix
: not as strongly needed because...Stability:
Community:
Now that we've built a thing... time for people to use 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