Nicholas Matsakis! Mozilla Research ! l ll e a r a P Systems programming without the hassle crashes! heisenbugs! fear 2 C/C++: efficiency first! destructors memory layout smart pointers monomorphization Research community! ML/Haskell: safety first! affine/ownership types region-based borrowing ADTs and pattern matching type inference no null pointers closures traits (typeclasses) 3 High-level coding // 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 Iterators. } Closures. 4 Assembly code 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 5 Higher-level coding fn foo(v: &[i32]) -> i32 { v.iter() .filter(|i| **i > 0) .map(|i| *i) .sum() } …generates the same assembly code. 6 Safe fn this_wont_compile(v: &mut Vec<i32>) -> i32 { let mut sum = 0; for &i in v.iter() { sum += i; Might free if i > 0 { v.push(0); } underlying buffer. } 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() { ^ 7 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(greater) ); } Sort left and right in parallel. 8 Parallel… and safe 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), Data race. || parallel_qsort(less) ); } error: closure requires unique access to `less` but it is already borrowed || parallel_qsort(less) ^~~~~~~~~~~~~~~~~~~~~~~ 9 Multiparadigm functional message-passing imperative mutable shared memory 10 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? https://www.flickr.com/photos/langtind/2217639550/in/photostream/ 12 No, it’s a double free! It’s a dangling pointer! No, it’s a data race! Simultaneous Aliasing and Mutation No, it’s iterator invalidation! 13 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 main() { fn sum(v: Vec<i32>) -> i32 { let mut v = vec![…]; let mut s = 0; let sum = sum(v); for i in 0..v.len() { println!(“{:?}”, sum); s += v[i]; … } } s } Give the vector to sum() Take ownership of a Vec<i32> Ownership 15 Compiler enforces moves fn main() { fn sum(v: Vec<i32>) -> i32 { let mut v = vec![…]; let mut s = 0; let sum = sum(v); for i in 0..v.len() { println!(“{:?}”, sum); s += v[i]; v[0] += 1; … } } s } 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); ^ 16 Two birds, one stone Ownership solves: - Memory management - Message passing - Strong encapsulation 17 fn main() { fn sum(v: &Vec<i32>) -> i32 { let mut v = vec![…]; let mut s = 0; let sum = sum(&v); for i in 0..v.len() { println!(“{:?}”, sum); s += v[i]; v[0] += 1; } } s } Lend the vector Take a reference to a Vec<i32> Shared borrow 18 fn main() { let mut v = vec![…]; sum(&mut v); v[0] += 1; } Lend the vector mutably fn sum(v: &mut Vec<i32>) { let mut s = 0; for i in 0..v.len() { s += v[i]; v[i] = s; } } Take a mutable reference to a Vec<i32> Mutable borrow 19 fn example() { let mut names = Vec::new(); names.push(..); names.push(..); let name = &names[1]; names.push(..); print(name); } Mutating the vector freed old contents. “brson” “pcwalton” “acrichto” names data “brson” length “pcwalton” capacity name Sharing: more than pointerpointer to same Danglingone pointer: memory. to freed memory. 20 Rust solution 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. 21 fn example() { let mut names = Vec::new(); names.push(“brson”); names.push(“pcwalton”); let name = &names[1]; names.push(“acrichto”); println!(“{:?}”, name); } Error: cannot mutate `names` while borrowed Borrow “locks” `names` until `name` goes out of scope http://is.gd/jeKW1E 22 Back to qsort 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( Creating closure || parallel_qsort(less), borrows `less` || parallel_qsort(less) mutably ); } This closure also needs a mutable borrow 23 Hack without fear! 24