Upgrade to Pro — share decks privately, control downloads, hide ads and more …

CppNow 2017

CppNow 2017

Keynote from CppNow 2017

nikomatsakis

May 16, 2017
Tweet

More Decks by nikomatsakis

Other Decks in Programming

Transcript

  1. 2

  2. 3 What Rust has to offer Strong safety guarantees… No

    seg-faults, no data-races, expressive type system. …without compromising on performance. No garbage collector, no runtime. Goal: Confident, productive systems programming
  3. 10 struct Event { } key: u32, name: InternedString, count:

    u32, Photo credit: Artaxerxes https://commons.wikimedia.org/wiki/File:Grindstone_Cafe_in_Lyndonville_Vermont.jpg
  4. 11 Photo credit: Gratisography https://www.pexels.com/photo/nature-walking-animal-strong-4075/ struct Event { } key:

    u32, name: InternedString, count: u32, struct InternedString { } value: Rc<String>, “reference-counted string” non-atomically reference-counted string
  5. 12 struct Event { } key: u32, name: InternedString, count:

    u32, Photo credit: Artaxerxes https://commons.wikimedia.org/wiki/File:Grindstone_Cafe_in_Lyndonville_Vermont.jpg error: the type `InternedString` does not implement `Send`
  6. 13 Zero-cost abstractions fn is_whitespace(text: &str) -> bool { text.chars()

    .all(|c| c.is_whitespace()) } fn load_images(paths: &[PathBuf]) -> Vec<Image> { paths.par_iter() .map(|path| Image::load(path)) .collect() }
  7. 14 Zero-cost abstractions Memory safety & data-race freedom + =

    Confident, productive systems programming
  8. 15 Rust the language Memory safety Traits Parallelism Unsafe Rust

    the community Rust in Firefox Community processes
  9. 17 Zero-cost abstractions Memory safety & data-race freedom + =

    Confident, productive systems programming
  10. Zero-cost abstractions void example() { vector<string> vector; … auto& elem

    = vector[0]; … } string [0] … elem vector data length capacity [0] [n] […] … ‘H’ … ‘e’ Stack and inline layout. Lightweight references Deterministic destruction Stack Heap C++
  11. void example() { vector<string> vector; … auto& elem = vector[0];

    vector.push_back(some_string); cout << elem; } vector data length capacity [0] … [0] [1] elem Aliasing: more than one pointer to same memory. Dangling pointer: pointer to freed memory. Mutating the vector freed old contents. C++ Memory safety
  12. fn main() { let mut book = Vec::new(); book.push(…); book.push(…);

    publish(book); publish(book); } fn publish(book: Vec<String>) { … } Ownership Take ownership of the vector 22 Error: use of moved value: `book` String book data length capacity [0] [1] data length capacity ~~~~~~~~~~~ Give ownership.
  13. void main() { vector<string> book(); book.push_back(…); book.push_back(…); publish(book); publish(book); }

    void publish(book: vector<string>) { … } Owns the vector 24 string book data length capacity [0] [1] data length capacity [0] [1] C++ Invoke copy ctor
  14. fn main() { let mut book = Vec::new(); book.push(…); book.push(…);

    publish(book.clone()); publish(book); } fn publish(book: Vec<String>) { … } 25 string book data length capacity [0] [1] [0] [1]
  15. 26 Moves compared with copy constructors: Moves compared with rvalue

    references: …in Rust, `clone()` is explicit.
  16. data length capacity data length capacity void main() { vector<string>

    book(); book.push_back(…); book.push_back(…); publish(std::move(book)); publish(book); } void publish(book: vector<string>) { … } 27 C++ string book data length capacity [0] [1]
  17. 28 …in Rust, enforced at compilation time. Moves compared with

    copy constructors: Moves compared with rvalue references: …in Rust, `clone()` is explicit.
  18. fn main() { let mut book = Vec::new(); book.push(…); book.push(…);

    publish(&book); publish(&book); } fn publish(book: &Vec<String>) { … } Shared borrow Change type to a reference to a vector 31 String book data length capacity [0] [1] Borrow the vector, creating a reference book
  19. cannot mutate while shared 32 “Don’t break your friend’s toys”

    let mut book = Vec::new(); book.push(…); { let r = &book; book.push(…); r.push(…); } book.push(…); book mutable here ~~~~~~~~~~~ book borrowed here ~~~~~~~~~ * Actually: mutation only under controlled circumstances * now book is mutable again r goes out of scope; borrow ends
  20. 33 fn example() { let mut vector = Vec::new(); …

    let elem = &vector[0]; vector.push(some_string); … } vector borrowed here cannot mutate here Revisit initial example ~~~~~~~~~~~~~~~~~~~~~
  21. ~ Ownership and Borrowing ~ Type Ownership T &T Alias?

    Mutate? Owned Shared reference ✓ ✓ &mut T Mutable reference ✓
  22. fn main() { let mut book = Vec::new(); book.push(…); book.push(…);

    edit(&mut book); edit(&mut book); } fn edit(book: &mut Vec<String>) { book.push(…); } Mutable borrow Mutable reference to a vector 35 String book data length capacity [0] [1] book [2] Mutable borrow [3]
  23. cannot access while borrowed but &mut ref can mutate 36

    “No, it’s my turn now!” let mut book = Vec::new(); book.push(…); { let r = &mut book; book.len(); r.push(…); } book.push(…); book mutable here ~~~~~~~~~ book borrowed here borrow ended; accessible again r goes out of scope; borrow ends
  24. ‘l 37 Lifetime of a reference let mut book =

    Vec::new(); … { let r: &String = &book[0]; … } let r: &String = &book; let r: &’l String = &book;
  25. 38 fn first<‘a>(v: &’a Vec<String>) -> &’a String { return

    &v[0]; } “Returns a reference derived from `v`” fn first(v: &Vec<String>) -> &String { return &v[0]; } (more common shorthand)
  26. 39 fn example() { let mut book = Vec::new(); {

    let r = first(&book); book.push(…); } } ~~~~~~~~~~~ book borrowed for this span Tracking borrows across functions fn first<‘a>(v: &’a Vec<String>) -> &’a String { return &v[0]; }
  27. 41 trait Clone { fn clone(&self) -> Self; } Implemented

    for a given type Method that borrows its receiver impl<T: Clone> Clone for Vec<T> { fn clone(&self) -> Vec<T> { let mut v = Vec::new(); for elem in self { v.push(elem.clone()); } return v; } } Implementation for vectors Create new vector Iterate (using references)… …push clone of each element. Return `v`
  28. 42 // “Safe to send between threads” trait Send {

    } // “Safe to memcpy” trait Copy { } String u32 Rc<String> u32 f32 String Rc<String> Marker traits ✅ Arc<String>
  29. Library-based concurrency 44 Originally: Rust had message passing built into

    the language. Now: library-based, multi-paradigm. Libraries leverage ownership and traits to avoid data races.
  30. fn qsort(vec: &mut [i32]) { 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); rayon::join(|| qsort(less), || qsort(greater)); } [0] [1] [2] [3] […] [n] vec: &mut [i32] less: &mut [i32] greater: &mut [i32] `&mut` can safely go between threads — because it is unaliased! fn split_at_mut<‘a>(v: &’a mut [T], …) -> (&’a mut [T], &’a mut [T])
  31. ~ Concurrency paradigms ~ Paradigm Fork-join Ownership? Borrowing? ✓ Message

    Passing Locking ✓ ✓ ✓ Lock-free Futures … ✓ ✓ ✓ ✓
  32. Safe abstractions unsafe { … } Ownership/borrowing/traits give tools to

    enforce safe abstraction boundaries. Trust me. fn split_at_mut(…) { } Validates input, etc. 49
  33. 51

  34. Our responsibility [after 1.0] is to ensure that you never

    dread upgrading Rust. Since the early days of Rust, there have only been two things you could count on: safety, and change. And sometimes not the first one. Rust 1.0: Stability as a deliverable
  35. ~ The feature pipeline ~ RFC Nightly Beta Stable 6

    week release cycle; only stable features {