Rust
Building blocks for fast code
1
2
There are many interesting programming languages
3
But I want to talk about Rust
Small Runtime Large Runtime
C Nim, D Java, Go
|-----|---|-----<--- GC Gap --->-----|----|--------|--------->
Assembly C++ Ocaml
4
5
Small Runtime Large Runtime
C Nim, D Java, Go
|-----|---|-----<--- GC Gap --->-----|----|--------|--------->
Assembly C++/Rust Ocaml
6
What can you do without GC?
7
What can you do without GC?
Not in this talk
8
This talk
Fast code
9
Cache rules
10
ArrayList<Foo>
*
Foo
*
Bar
*
*
Foo
*
Bar
Foo
*
Bar
Ideal ArrayList<Foo>
*
*
*
Foo
Bar
Foo
Bar
Foo
Bar
Modern C++
1 #include <iostream> �2 #include <vector> �3 �4 int main() { �5 std::vector<int> xs = {1, 2, 4, 5};�6 auto& x = xs[0]; �7 xs.push_back(6); �8 std::cout << x << std::endl; �9 }
13
Modern C++
1 #include <iostream> �2 #include <vector> �3 �4 int main() { �5 std::vector<int> xs = {1, 2, 4, 5};�6 auto& x = xs[0]; �7 xs.push_back(6); �8 std::cout << x << std::endl; �9 }
$ clang++ --std=c++14 -Wall -pedantic ./main.cpp
$ ./a.out
0
14
1 fn main() { �2 println!("Hello, World!"); �3 }
15
Rules
Every value has a single owner
A reference can not outlive value owner
Shared XOR Mutable
16
Ownership
1 fn main() { �2 let mut xs = vec![1, 2, 3, 4]; // Heap allocated vector �3 xs.push(5); �4 // Drop `xs` here �5 }
17
Ownership
1 struct Foo { �2 ints: Vec<i32> �3 } �4 �5 impl Foo { �6 fn new(xs: Vec<i32>) -> Foo { �7 return Foo { ints: xs }; �8 } �9 }
18
Ownership
1 struct Foo { �2 ints: Vec<i32> �3 } �4 �5 impl Foo { �6 fn new(xs: Vec<i32>) -> Foo { �7 return Foo { ints: xs }; �8 } �9 }
1 fn main() { �2 let mut xs = vec![1, 2, 3, 4]; �3 xs.push(5); �4 let foo = Foo::new(xs); �5 // No `xs` any more! �6 // Drop `foo` here �7 }
19
Ownership
1 struct Foo { �2 ints: Vec<i32> �3 } �4 �5 impl Foo { �6 fn new(xs: Vec<i32>) -> Foo { �7 return Foo { ints: xs }; �8 } �9 }
error[E0382]: use of moved value: `xs`
1 fn main() { �2 let mut xs = vec![1, 2, 3, 4]; �3 xs.push(5); �4 let foo = Foo::new(xs); �5 xs.push(92); �6 �7 }
20
References
1 fn sum(xs: &Vec<i32>) -> i32 { �2 xs.iter().sum() �3 } �4 �5 fn main() { �6 let xs = vec![1, 2, 3, 4]; �7 let total = sum(&xs); �8 println!("sum = {}", total); �9 }
21
Shared ^ Mutable
1 fn main() { �2 let mut x: i32 = 92; �3 let r1: &i32 = &x; �4 let r2: &i32 = &x; �5 }
1 fn main() { �2 let mut x: i32 = 92; �3 let r: &mut i32 = &mut x; �4 }
22
Shared ^ Mutable
1 fn main() { �2 let mut x: i32 = 92; �3 let r1: &mut i32 = &mut x; �4 let r2: &i32 = &x; �5 }
error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
--> shared_xor_mutable.rs:4:21
|
3 | let r1: &mut i32 = &mut x;
| - mutable borrow occurs here
4 | let r2: &i32 = &x;
| ^ immutable borrow occurs here
5 | }
| - mutable borrow ends here
error: aborting due to previous error
23
Shared ^ Mutable
1 fn main() { �2 let mut xs = vec![1, 2, 3, 4]; �3 let x: &i32 = &xs[0]; �4 xs.push(92); �5 }
error[E0502]: cannot borrow `xs` as mutable because it is also borrowed as immutable
--> vector.rs:4:5
|
3 | let x: &i32 = &xs[0];
| -- immutable borrow occurs here
4 | xs.push(92);
| ^^ mutable borrow occurs here
5 | }
| - immutable borrow ends here
error: aborting due to previous error
24
Shared ^ Mutable
1 fn push_all(xs: &mut Vec<i32>, ys: &Vec<i32>) { �2 for &y in ys { �3 xs.push(y); �4 } �5 } �6 �7 fn main() { �8 let mut xs = vec![1, 2, 3, 4]; �9 let ys = vec![1, 2, 3, 4]; �10 push_all(&mut xs, &ys); �11 }
25
Shared ^ Mutable
1 fn push_all(xs: &mut Vec<i32>, ys: &Vec<i32>) { �2 for &y in ys { �3 xs.push(y); �4 } �5 } �6 �7 fn main() { �8 let mut xs = vec![1, 2, 3, 4]; �9 let ys = vec![1, 2, 3, 4]; �10 push_all(&mut xs, &xs); �11 }
error[E0502]: cannot borrow `xs` as mutable because it is also borrowed as immutable
26
1 fn main() { �2 std::thread::spawn(|| { �3 println!("Hello, World!"); �4 }); �5 }
27
1 �2 �3 fn main() { �4 let xs = vec![1, 2, 3, 4]; �5 std::thread::spawn(|| { �6 println!("{:?}", xs); �7 }); �8 }
28
1 �2 �3 fn main() { �4 let xs = vec![1, 2, 3, 4]; �5 std::thread::spawn(|| { �6 println!("{:?}", xs); �7 }); �8 }
error[E0373]: closure may outlive the current function, but it borrows `xs`, which is owned by the current function
29
1 �2 �3 fn main() { �4 let xs = vec![1, 2, 3, 4]; �5 std::thread::spawn(move || { �6 println!("{:?}", xs); �7 }); �8 // No `xs` here �9 }
30
1 use std::sync::mpsc::channel; �2 �3 fn main() { �4 let (tx, rx) = channel(); �5 �6 std::thread::spawn(move || { �7 let xs = rx.recv().unwrap(); �8 println!("{:?}", xs); �9 }); �10 �11 let xs = vec![1, 2, 3, 4]; �12 tx.send(xs).unwrap(); // No copy here! �13 }
31
1 �2 �3 fn main() { �4 let mut xs = [0, 0, 0, 0]; // Stack allocated array �5 �6 �7 for i in &mut xs { �8 �9 *i += 1; �10 �11 } �12 �13 �14 println!("{:?}", xs); �15 }
32
1 extern crate crossbeam; �2 �3 fn main() { �4 let mut xs = [0, 0, 0, 0]; �5 �6 crossbeam::scope(|scope| { �7 for i in &mut xs { �8 scope.spawn(move || { �9 *i += 1; // Stack of another thread! �10 }); �11 } �12 }); �13 �14 println!("{:?}", xs); �15 }
33
1 extern crate crossbeam; �2 �3 fn main() { �4 let mut xs = [0, 0, 0, 0]; �5 �6 crossbeam::scope(|scope| { �7 for i in &mut xs { �8 scope.spawn(move || *i += 1 ); �9 scope.spawn(move || *i += 1 ); �10 } �11 }); �12 }
error[E0382]: capture of moved value: `i`
34
1 fn main() { �2 let xs = std::sync::Mutex::new([0, 0, 0, 0]); // Protect the data �3 crossbeam::scope(|scope| { �4 for _ in 0..10 { �5 scope.spawn(|| { �6 let mut guard = xs.lock().unwrap(); �7 let xs: &mut [i32; 4] = &mut guard; // Can't leak `xs` �8 for i in xs { �9 *i += 1; �10 } �11 }); �12 } �13 }); �14 println!("{:?}", *xs.lock().unwrap()); �15 }
35
Rust is
36