Rust
Alexey Kladov
There are
But I want to talk about Rust
Small Runtime Large Runtime
C Nim, D Java, Go
|-----|---|-----<--- GC Gap --->-----|----|--------|--------->
Assembly C++ Ocaml
Small Runtime Large Runtime
C Nim, D Java, Go
|-----|---|-----<--- GC Gap --->-----|----|--------|--------->
Assembly C++/Rust Ocaml
Resource management
No GC, no undefined behaviour, no iterator invalidation, no data races.
Zero overhead in most cases.
Safety
Concurrency
No data races
Mutable state
Not a joke
* Rust uses LLVM, C/C++ uses gcc
Language does not matter (R.I.P. Dylan)
Rust sucks
fn main() {
println!("Hello, World!");
}
The mix
C++
ML
Cyclone
Rules
A value has exactly one owner (at any given time-point)
A reference does not outlive the owner
Shared xor mutable
Ownership
fn main() {
let mut xs = vec![1, 2, 3]; // Heap allocated vector
xs.push(4);
// Drop `xs` here
}
Ownership
struct Foo {
ints: Vec<i32>
}
impl Foo {
fn new(xs: Vec<i32>) -> Foo {
return Foo { ints: xs };
}
}
Ownership
struct Foo {
ints: Vec<i32>
}
impl Foo {
fn new(xs: Vec<i32>) -> Foo {
return Foo { ints: xs };
}
}
fn main() {
let mut xs = vec![1, 2, 3];
xs.push(4);
let foo = Foo::new(xs);
// Drop `foo` here
}
Ownership
struct Foo {
ints: Vec<i32>
}
impl Foo {
fn new(xs: Vec<i32>) -> Foo {
return Foo { ints: xs };
}
}
error: use of moved value: `xs` [E0382]
xs.push(92)
^~
help: run `rustc --explain E0382` to see a detailed explanation
fn main() {
let mut xs = vec![1, 2, 3];
xs.push(4);
let foo = Foo::new(xs);
xs.push(92);
}
Borrowing
fn sum(xs: &Vec<i32>) -> i32 {
xs.iter().sum()
}
�fn main() {
let xs = vec![1, 2, 3];
let total = sum(&xs);
println!("sum = {}", total);
}
Shared ^ Mutable
fn main() {
let mut x: i32 = 92;
let r1: &i32 = &x;
let r2: &i32 = &x;
}
fn main() {
let mut x: i32 = 92;
let r: &mut i32 = &mut x;
}
Shared ^ Mutable
fn main() {
let mut x: i32 = 92;
let r1: &mut i32 = &mut x;
let r2: &i32 = &x;
}
error: cannot borrow `x` as immutable because it is also borrowed as mutable
let r2: &i32 = &x;
^
note: previous borrow of `x` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `x` until the borrow ends
let r1: &mut i32 = &mut x;
^
Shared ^ Mutable
fn main() {
let mut xs = vec![1, 2, 3];
let x: &i32 = &xs[0];
xs.push(92);
}
error: cannot borrow `xs` as mutable because it is also borrowed as immutable
xs.push(92);
^~
note: previous borrow of `xs` occurs here; the immutable borrow prevents subsequent moves or mutable borrows of `xs` until the borrow ends
let x: &i32 = &xs[0];
Shared ^ Mutable
fn push_all(xs: &mut Vec<i32>, ys: &Vec<i32>) {
for &y in ys {
xs.push(y);
}
}
�fn main() {
let mut xs = vec![1, 2, 3];
let ys = vec![1, 2, 3];
push_all(&mut xs, &ys);
}
Shared ^ Mutable
fn push_all(xs: &mut Vec<i32>, ys: &Vec<i32>) {
for &y in ys {
xs.push(y);
}
}
�fn main() {
let mut xs = vec![1, 2, 3];
let ys = vec![1, 2, 3];
push_all(&mut xs, &xs);
}
error: cannot borrow `xs` as immutable because it is also borrowed as mutable
fn main() {
std::thread::spawn(|| {
println!("Hello, World!");
});
}
fn main() {
let xs = vec![1, 2, 3];
std::thread::spawn(|| {
println!("{:?}", xs);
});
}
fn main() {
let xs = vec![1, 2, 3];
std::thread::spawn(|| {
println!("{:?}", xs);
});
}
error: closure may outlive the current function, but it borrows `xs`, which is owned by the current function
fn main() {
let xs = vec![1, 2, 3];
std::thread::spawn(move || {
println!("{:?}", xs);
});
// No `xs` here
}
use std::sync::mpsc::channel;
fn main() {
let (tx, rx) = channel();
std::thread::spawn(move || {
let xs = rx.recv().unwrap();
println!("{:?}", xs);
});
let xs = vec![1, 2, 3];
tx.send(xs).unwrap(); // No copy here!
}
fn main() {
let mut xs = [0, 0, 0, 0]; // Stack allocated array
for i in &mut xs {
*i += 1;
}
println!("{:?}", xs);
}
extern crate crossbeam;
fn main() {
let mut xs = [0, 0, 0, 0];
crossbeam::scope(|scope| {
for i in &mut xs {
scope.spawn(move || {
*i += 1; // Stack of another thread!
});
}
});
println!("{:?}", xs);
}
extern crate crossbeam;
fn main() {
let mut xs = [0, 0, 0, 0];
crossbeam::scope(|scope| {
for i in &mut xs {
scope.spawn(move || {
*i += 1; // Stack of another thread!
});
}
});
println!("{:?}", xs);
}
extern crate crossbeam;
fn main() {
let mut xs = [0, 0, 0, 0];
crossbeam::scope(|scope| {
for i in &mut xs {
scope.spawn(move || *i += 1 );
scope.spawn(move || *i += 1 );
}
});
}
error: capture of moved value: `i` [E0382]
extern crate crossbeam;
fn main() {
let mut xs = [0, 0, 0, 0];
crossbeam::scope(|scope| {
for i in &mut xs {
scope.spawn(move || *i += 1 );
scope.spawn(move || *i += 1 );
}
});
}
We’re borrowing xs here
We’re borrowing i (which is an iterator for xs) here
And here...
extern crate crossbeam;
fn main() {
let mut xs = [0, 0, 0, 0];
crossbeam::scope(|scope| {
for i in &mut xs {
scope.spawn(move || *i += 1 );
scope.spawn(move || *i += 1 );
}
});
}
error: capture of moved value: `i` [E0382]
We’re borrowing xs here
We’re borrowing i (which is an iterator for xs) here
And here...
fn main() {
let xs = std::sync::Mutex::new([0, 0, 0, 0]); // Protect the data
crossbeam::scope(|scope| {
for _ in 0..10 {
scope.spawn(|| {
let mut guard = xs.lock().unwrap();
let xs: &mut [i32; 4] = &mut guard; // Can't leak `xs`
for i in xs {
*i += 1;
}
});
}
});
println!("{:?}", *xs.lock().unwrap());
}
extern crate rayon;
fn quick_sort(xs: &mut[i32]) {
if xs.len() <= 1 { return }
let mid = partition(xs);
let (lo, hi) = xs.split_at_mut(mid);
rayon::join(|| quick_sort(lo), || quick_sort(hi));
}
fn partition(xs: &mut[i32]) -> usize { /* … */ }
fn main() {
let mut xs = [1, 3, 0, 6, 2, 4, 92];
quick_sort(&mut xs);
}
Links