Upload
others
View
3
Download
0
Embed Size (px)
Citation preview
Nicholas Matsakis!Mozilla Research
2
Systems programming without the hasslecrashes!heisenbugs!fear
Parallel!
3
C/C++: efficiency first!destructors memory layout smart pointers monomorphization
ML/Haskell: safety first!ADTs and pattern matching type inference no null pointers closures traits (typeclasses)
Research community!affine/ownership types region-based borrowing
// sums all the positive values in `v` fn sum_pos(v: &[i32]) -> i32 { let mut sum = 0; for i in v.iter().filter(|i| **i > 0) { sum += *i; } sum }
High-level coding
4
Iterators.
Closures.
Assembly code
5
leaq (%rdi,%rsi,4), %rcx xorl %eax, %eax jmp .LBB5_1 .LBB5_3: addl %edx, %eax .align 16, 0x90 .LBB5_1: cmpq %rdi, %rcx je .LBB5_4 movl (%rdi), %edx addq $4, %rdi testl %edx, %edx jle .LBB5_1 jmp .LBB5_3 .LBB5_4: retq
fn foo(v: &[i32]) -> i32 { v.iter() .filter(|i| **i > 0) .map(|i| *i) .sum() }
Higher-level coding
6
…generates the same assembly code.
Safe
7
fn this_wont_compile(v: &mut Vec<i32>) -> i32 { let mut sum = 0; for &i in v.iter() { sum += i; if i > 0 { v.push(0); } } sum }
error: cannot borrow `*v` as mutable because it is also borrowed as immutable if i > 0 { v.push(0); } ^ note: previous borrow of `*v` occurs here; the immutable borrow prevents subsequent moves or mutable borrows of `*v` until the borrow ends for &i in v.iter() { ^
Might free underlying buffer.
fn parallel_qsort(vec: &mut [int]) { if vec.len() <= 1 { return; } let pivot = vec[random(vec.len())]; let mid = vec.partition(vec, pivot); let (less, greater) = vec.split_at_mut(mid); parallel::join( || parallel_qsort(less), || parallel_qsort(greater) ); }
Parallel
8
Sort left and right in parallel.
fn parallel_qsort(vec: &mut [int]) { if vec.len() <= 1 { return; } let pivot = vec[random(vec.len())]; let mid = vec.partition(vec, pivot); let (less, greater) = vec.split_at_mut(mid); parallel::join( || parallel_qsort(less), || parallel_qsort(less) ); }
Parallel… and safe
9
error: closure requires unique access to `less` but it is already borrowed || parallel_qsort(less) ^~~~~~~~~~~~~~~~~~~~~~~
Data race.
Multiparadigm
10
message-passing
mutable shared memory
functional
imperative
Open and welcoming
Rust has been open source from the beginning. !
Open governance model based on public RFCs. !
We have an active, amazing community.
❤
11
Whither Safety?
12https://www.flickr.com/photos/langtind/2217639550/in/photostream/
13
It’s a dangling pointer!
No, it’s a data race!
No, it’s a double free!
Simultaneous Aliasing and
Mutation
No, it’s iterator
invalidation!
The Big Idea
Ownership and borrowing:!!1. All memory has a clear owner. 2. Others can borrow from the owner. 3. Owner cannot free or mutate the
memory while it is borrowed.
14
fn sum(v: Vec<i32>) -> i32 { let mut s = 0; for i in 0..v.len() { s += v[i]; } s }
Ownership 15
fn main() { let mut v = vec![…]; let sum = sum(v); println!(“{:?}”, sum); … }
Take ownership of a Vec<i32>
Give the vector to sum()
fn sum(v: Vec<i32>) -> i32 { let mut s = 0; for i in 0..v.len() { s += v[i]; } s }
fn main() { let mut v = vec![…]; let sum = sum(v); println!(“{:?}”, sum); … } v[0] += 1;
Compiler enforces moves
16
error: use of moved value: `v` v[0] += 1; ^ note: `v` moved here because it has type `Vec<i32>`, which is non-copyable let sum = sum(v); ^
Two birds, one stone
17
Ownership solves: - Memory management - Message passing - Strong encapsulation
fn main() { let mut v = vec![…]; let sum = sum(&v); println!(“{:?}”, sum); v[0] += 1; }
fn sum(v: &Vec<i32>) -> i32 { let mut s = 0; for i in 0..v.len() { s += v[i]; } s }
Shared borrow
Take a reference to a Vec<i32>
18
Lend the vector
fn main() { let mut v = vec![…]; sum(&mut v); v[0] += 1; }
fn sum(v: &mut Vec<i32>) { let mut s = 0; for i in 0..v.len() { s += v[i]; v[i] = s; } }
Mutable borrow
Take a mutable reference to a Vec<i32>
19
Lend the vector mutably
fn example() { let mut names = Vec::new(); names.push(..); names.push(..); let name = &names[1]; names.push(..); print(name); }
names
data
length
capacity
“brson”
“pcwalton”
name
“brson”
“pcwalton”
“acrichto”
Sharing: more than one pointer to same memory.
Dangling pointer: pointer to freed memory.
Mutating the vector freed old contents.
20
Rust solution
21
Compile-time read-write-lock:!!Creating a shared reference to X “read locks” X. - Other readers OK. - No writers. - Lock lasts until reference goes out of scope. !Creating a mutable reference to X “writes locks” X. - No other readers or writers. - Lock lasts until reference goes out of scope.
Never have a reader/writer at same time.
fn example() { let mut names = Vec::new(); names.push(“brson”); names.push(“pcwalton”); let name = &names[1]; names.push(“acrichto”); println!(“{:?}”, name); }
Borrow “locks” `names` until `name` goes out of scopeError: cannot mutate
`names` while borrowed
22http://is.gd/jeKW1E
fn parallel_qsort(vec: &mut [int]) { if vec.len() <= 1 { return; } let pivot = vec[random(vec.len())]; let mid = vec.partition(vec, pivot); let (less, greater) = vec.split_at_mut(mid); parallel::join( || parallel_qsort(less), || parallel_qsort(less) ); }
Back to qsort
23
Creating closure borrows `less`
mutably
This closure also needs a
mutable borrow
24
Hack without fear!