SlideShare a Scribd company logo
1
Rust: Reach Further!
Nicholas Matsakis
2
Safe, fast code
that works.
Rust:
3
Safe
Double free?
Buffer overflow?
Dangling pointers?
Data races?
GC
😱
😱
😱
😱
😀
😀
😀
😱
😎
😎
😎
😎
4
Safety =
Eat your spinach!
Photo credit: Sanjoy Ghosh
https://www.flickr.com/photos/sanjoy/4016632253/
5
Photo credit: Salim Virji
https://www.flickr.com/photos/salim/8594532469/
Safety = Eat your spinach!
6
The Rust compiler just saved me from a nasty threading bug. I was
working on cage (our open source development tool for Docker apps with
lots of microservices), and I decided to parallelize the routine that
transformed docker-compose.yml files.
7
Safe, fast code
that works.
Rust:
8
Fast
Zero-cost abstractions:
High-level code, low-level efficiency
No garbage collector:
Predictable, memory usage; no pauses
No compiler heroics needed
Apply techniques to other resources (sockets, etc)
Indeed, no mandatory runtime at all:
Embedded, WASM, or standalone libraries
9
Performance
class ::String
def blank?
/A[[:space:]]*z/ == self
end
end
Ruby:
964K iter/sec
static VALUE
rb_str_blank_as(VALUE str)
{
rb_encoding *enc;
char *s, *e;
enc = STR_ENC_GET(str);
s = RSTRING_PTR(str);
if (!s || RSTRING_LEN(str) == 0) return Qtrue;
e = RSTRING_END(str);
while (s < e) {
int n;
unsigned int cc = rb_enc_codepoint_len(s, e, &n, enc);
switch (cc) {
case 9:
case 0xa:
case 0xb:
case 0xc:
case 0xd:
case 0x20:
case 0x85:
case 0xa0:
case 0x1680:
case 0x2000:
case 0x2001:
case 0x2002:
case 0x2003:
case 0x2004:
case 0x2005:
case 0x2006:
case 0x2007:
case 0x2008:
case 0x2009:
case 0x200a:
case 0x2028:
case 0x2029:
case 0x202f:
case 0x205f:
case 0x3000:
#if ruby_version_before_2_2()
case 0x180e:
#endif
/* found */
break;
default:
return Qfalse;
}
s += n;
}
return Qtrue;
}
Performance
Ruby:
964K iter/sec
C:
10.5M iter/sec
10x!
https://github.com/SamSaffron/fast_blank
Performance
11
class ::String
def blank?
/A[[:space:]]*z/ == self
end
end
extern “C” fn fast_blank(buf: Buf) -> bool {
buf.as_slice().chars().all(|c| c.is_whitespace())
}
Get Rust
string slice
Get iterator over
each character
Are all characters
whitespace?
Rust:
11M iter/sec
Ruby:
964K iter/sec
C:
10.5M iter/sec
12
High-level, 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()
}
13
Safe, fast code
that works.
Rust:
14
I like Rust because it is boring.
— CJ Silverio, npm CTO
15
From http://jvns.ca/blog/2016/09/11/rustconf-keynote/
Open and welcoming
16
Ownership and Borrowing
Parallelism in Rust
Rust in Production
Unsafe Rust
17
Ownership and BorrowingPhoto Credit: Nathan Kam
https://www.youtube.com/watch?v=Tnssn9KcWLg
18
“Must be this
tall to write
multi-threaded
code”
David Baron

Mozilla Distinguished Engineer
Data races
Sharing
Mutation
No ordering
Data race
19
Actor-based languages
Functional languages
Sequential programming
Data races
Sharing
Mutation
No ordering
Data race
20
(Or enforce ordering 

via API.)
Rust: No sharing and

mutation at the same time.
Type Ownership Alias? Mutate?
T Owned ✓
~ Ownership and borrowing ~
fn main() {
let mut book = Vec::new();
book.push(…);
book.push(…);
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.
publish(book);
23
“Manual” memory management in Rust:
Values owned by creator.
Values moved via assignment.
When final owner returns, value is freed.
Feels
invisible.]
void main() {
Vector book = …;
publish(book);
publish(book);
}
void publish(Vector book) {
…
}
“Ownership” in Java
Take reference
to Vector
24
new Thread(…);JavaCode
~ Ownership and borrowing ~
Type Ownership
T
Alias? Mutate?
Owned ✓
&T Shared reference ✓
fn lender() {
let mut vec = Vec::new();
vec.push(1);
vec.push(2);
use(&vec);
…
}
fn use(vec: &Vec<int>) {
}
1
2vec
data
length
capacity
vec
“Shared reference
toVec<int>”
Loan out vec
…
~~~~~~~~~
let mut book = Vec::new();
book.push(…);
let r = &book;
book.len();
book.push(…);
r.push(…);
book.push(…);
reading `book` ok while shared
cannot mutate while shared
27
Sharing “freezes” data (temporarily)
`book` mutable here
~~~~~~~~~~~
`book` borrowed here
after last use of `r`, 

`book` is mutable again
cannot mutate through shared ref
~ Ownership and borrowing ~
Type Ownership
T
&T
Alias? Mutate?
Owned
Shared reference
✓
✓
&mut T Mutable reference ✓
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
29
String
book
data
length
capacity
[0]
[1]
book
[2]
Mutable borrow
[3]
cannot access while borrowed
but can mutate through `r`
30
Mutable references: no other access
book mutable here
~~~~~~~~~
book borrowed here
after last use of `r`, 

book is accessible again
let mut book = Vec::new();
book.push(…);
let r = &mut book;
book.len();
r.push(…);
book.push(…);
31
Definition: a closure is a callback that Just Works.
— The Reinvigorated Programmer
https://reprog.wordpress.com/2010/02/27/closures-finally-explained/
~ Closures ~
32
0counter
creates a closure
closure borrows `counter` from
enclosing stack frame
closure
1
cannot access while borrowed
done using closure; ok
2 3
~~~~~~~~~~~
fn main() {
let mut counter = 0;
let mut closure = || {
counter += 1;
};
closure();
counter += 1;
closure();
counter += 1;
}
33
There are 2 hard problems in computer science:
cache invalidation, naming things, and off-by-one
errors.

— Leon Bambrick
~ Named lifetimes ~
34
impl<T> [T] {
fn split_at_mut(
&’a mut self,
mid: usize,
) -> (&’a mut [T], &’a mut [T]) {
…
}
}
given a slice of T elements…
[0] [1] [2] [3] […] [n]
self: &mut [i32]
less: &mut [i32] greater: &mut [i32]
and a midpoint
divide slice into two
fn foo(vec: &mut [T]) {
let (less, greater) =
vec.split_at_mut(3);
…
} `vec` borrowed here
while `less` and
`greater` still in use
35
Parallelism
Photo credit: Dave Gingrich
https://www.flickr.com/photos/ndanger/2744507570/
36
Observation:
Building parallel abstractions is easy.
Misusing those abstractions is also easy.
func foo(…) {
m := make(map[string]string)
m[“Hello”] = “World”
channel <- m
m[“Hello”] = “Data Race”
}
send data over channel
but how to stop sender from

using it afterwards?
GoCode
37
fn foo(…) {
let m = HashMap::new();
m.insert(“Hello”, “World”);
channel.send(m);
m.insert(“Hello”, “Data Race”);
}
impl<T> Channel<T> {
fn send(&mut self, data: T) {
…
}
}
Take ownership
of the data
Error: use of moved
value: `book`
~~~~~~~~~~~~~~~~~~~~~~~~~~
~ Concurrency paradigms ~
Paradigm
Message passing
Ownership? Borrowing?
✓
Locking ✓ ✓
0
fn sync_inc(mutex: &Mutex<i32>) {
let mut guard: Guard<i32> = counter.lock();
*guard += 1;
}
https://commons.wikimedia.org/wiki/File:No-DRM_lock.svg
1
mutex
guard
~ Concurrency paradigms ~
Paradigm
Message passing
Ownership? Borrowing?
✓
Locking ✓ ✓
Fork join ✓
41
fn divide_and_conquer(…) {
rayon::join(
|| do_something(),
|| do_something_else(),
);
}
Conceptually:
- Start two threads
- Wait for them to finish
[0] [1] [2] [3] […] [n]
vec: &mut [i32]
less: &mut [i32] greater: &mut [i32]
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);
qsort(less);
qsort(greater);
}
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]
rayon::join(
|| qsort(less),
|| qsort(less),
);
?~~~~~~~~~
~ Concurrency paradigms ~
Paradigm
Message passing
Ownership? Borrowing?
✓
Locking
Fork join
✓ ✓
✓
Lock-free
Futures
…
✓ ✓
✓ ✓
45
Unsafe
46
Vision: An Extensible Language
Core language:
Ownership and borrowing
Libraries:
Reference-counting
Files
Parallel execution
…
Use ownership/
borrowing to enforce
correct usage.
]
Safe abstractions
unsafe {
…
}
Ownership/borrowing/traits give tools to
enforce safe abstraction boundaries.
Trust me.
fn split_at_mut(…) {
}
Validates input, etc.
47
48
Stylo (Parallel CSS Rendering — coming in FF57)
Total KLOC Unsafe KLOC Unsafe %
Total 146.2 51.7 35%
Interesting stuff 71.6 1.4 1.9%
FFI Bindings 74.5 50.3 67.4%
49
50
51
52
Photo credit: Salim Virji
https://www.flickr.com/photos/salim/8594532469/
Safety = Eat your spinach!
53
0
25
50
75
100
Amazon YouTube YouTube (32 bit)
Initial load times (relative to today)
Amdahl’s Line
Page
Layo
ut
O
ther
stuff
54
Gradual adoption
works.
55
Community
Photo credit: David McSpadden
https://www.flickr.com/photos/familyclan/15535822737/
56
Rust Leadership Structure
Team Members Peers
Core 9
Language 6 5
Libraries 7 1
Compiler 9
Dev Tools 6 11
Cargo 6
Infrastructure 10
Community 13
Documentation 4
Moderation 5
58 people
10 Mozilla (17%)
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
58
RFC Process
The Rust Roadmap
60
Want to learn more?
intorust.comrust-lang.orgO’Reilly
Book, 2nd ed. ScreencastsPre-order now!

More Related Content

Rust: Reach Further

  • 2. 2 Safe, fast code that works. Rust:
  • 3. 3 Safe Double free? Buffer overflow? Dangling pointers? Data races? GC 😱 😱 😱 😱 😀 😀 😀 😱 😎 😎 😎 😎
  • 4. 4 Safety = Eat your spinach! Photo credit: Sanjoy Ghosh https://www.flickr.com/photos/sanjoy/4016632253/
  • 5. 5 Photo credit: Salim Virji https://www.flickr.com/photos/salim/8594532469/ Safety = Eat your spinach!
  • 6. 6 The Rust compiler just saved me from a nasty threading bug. I was working on cage (our open source development tool for Docker apps with lots of microservices), and I decided to parallelize the routine that transformed docker-compose.yml files.
  • 7. 7 Safe, fast code that works. Rust:
  • 8. 8 Fast Zero-cost abstractions: High-level code, low-level efficiency No garbage collector: Predictable, memory usage; no pauses No compiler heroics needed Apply techniques to other resources (sockets, etc) Indeed, no mandatory runtime at all: Embedded, WASM, or standalone libraries
  • 9. 9 Performance class ::String def blank? /A[[:space:]]*z/ == self end end Ruby: 964K iter/sec
  • 10. static VALUE rb_str_blank_as(VALUE str) { rb_encoding *enc; char *s, *e; enc = STR_ENC_GET(str); s = RSTRING_PTR(str); if (!s || RSTRING_LEN(str) == 0) return Qtrue; e = RSTRING_END(str); while (s < e) { int n; unsigned int cc = rb_enc_codepoint_len(s, e, &n, enc); switch (cc) { case 9: case 0xa: case 0xb: case 0xc: case 0xd: case 0x20: case 0x85: case 0xa0: case 0x1680: case 0x2000: case 0x2001: case 0x2002: case 0x2003: case 0x2004: case 0x2005: case 0x2006: case 0x2007: case 0x2008: case 0x2009: case 0x200a: case 0x2028: case 0x2029: case 0x202f: case 0x205f: case 0x3000: #if ruby_version_before_2_2() case 0x180e: #endif /* found */ break; default: return Qfalse; } s += n; } return Qtrue; } Performance Ruby: 964K iter/sec C: 10.5M iter/sec 10x! https://github.com/SamSaffron/fast_blank
  • 11. Performance 11 class ::String def blank? /A[[:space:]]*z/ == self end end extern “C” fn fast_blank(buf: Buf) -> bool { buf.as_slice().chars().all(|c| c.is_whitespace()) } Get Rust string slice Get iterator over each character Are all characters whitespace? Rust: 11M iter/sec Ruby: 964K iter/sec C: 10.5M iter/sec
  • 12. 12 High-level, 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() }
  • 13. 13 Safe, fast code that works. Rust:
  • 14. 14 I like Rust because it is boring. — CJ Silverio, npm CTO
  • 16. 16 Ownership and Borrowing Parallelism in Rust Rust in Production Unsafe Rust
  • 17. 17 Ownership and BorrowingPhoto Credit: Nathan Kam https://www.youtube.com/watch?v=Tnssn9KcWLg
  • 18. 18 “Must be this tall to write multi-threaded code” David Baron
 Mozilla Distinguished Engineer
  • 19. Data races Sharing Mutation No ordering Data race 19 Actor-based languages Functional languages Sequential programming
  • 20. Data races Sharing Mutation No ordering Data race 20 (Or enforce ordering 
 via API.) Rust: No sharing and
 mutation at the same time.
  • 21. Type Ownership Alias? Mutate? T Owned ✓ ~ Ownership and borrowing ~
  • 22. fn main() { let mut book = Vec::new(); book.push(…); book.push(…); 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. publish(book);
  • 23. 23 “Manual” memory management in Rust: Values owned by creator. Values moved via assignment. When final owner returns, value is freed. Feels invisible.]
  • 24. void main() { Vector book = …; publish(book); publish(book); } void publish(Vector book) { … } “Ownership” in Java Take reference to Vector 24 new Thread(…);JavaCode
  • 25. ~ Ownership and borrowing ~ Type Ownership T Alias? Mutate? Owned ✓ &T Shared reference ✓
  • 26. fn lender() { let mut vec = Vec::new(); vec.push(1); vec.push(2); use(&vec); … } fn use(vec: &Vec<int>) { } 1 2vec data length capacity vec “Shared reference toVec<int>” Loan out vec …
  • 27. ~~~~~~~~~ let mut book = Vec::new(); book.push(…); let r = &book; book.len(); book.push(…); r.push(…); book.push(…); reading `book` ok while shared cannot mutate while shared 27 Sharing “freezes” data (temporarily) `book` mutable here ~~~~~~~~~~~ `book` borrowed here after last use of `r`, 
 `book` is mutable again cannot mutate through shared ref
  • 28. ~ Ownership and borrowing ~ Type Ownership T &T Alias? Mutate? Owned Shared reference ✓ ✓ &mut T Mutable reference ✓
  • 29. 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 29 String book data length capacity [0] [1] book [2] Mutable borrow [3]
  • 30. cannot access while borrowed but can mutate through `r` 30 Mutable references: no other access book mutable here ~~~~~~~~~ book borrowed here after last use of `r`, 
 book is accessible again let mut book = Vec::new(); book.push(…); let r = &mut book; book.len(); r.push(…); book.push(…);
  • 31. 31 Definition: a closure is a callback that Just Works. — The Reinvigorated Programmer https://reprog.wordpress.com/2010/02/27/closures-finally-explained/ ~ Closures ~
  • 32. 32 0counter creates a closure closure borrows `counter` from enclosing stack frame closure 1 cannot access while borrowed done using closure; ok 2 3 ~~~~~~~~~~~ fn main() { let mut counter = 0; let mut closure = || { counter += 1; }; closure(); counter += 1; closure(); counter += 1; }
  • 33. 33 There are 2 hard problems in computer science: cache invalidation, naming things, and off-by-one errors.
 — Leon Bambrick ~ Named lifetimes ~
  • 34. 34 impl<T> [T] { fn split_at_mut( &’a mut self, mid: usize, ) -> (&’a mut [T], &’a mut [T]) { … } } given a slice of T elements… [0] [1] [2] [3] […] [n] self: &mut [i32] less: &mut [i32] greater: &mut [i32] and a midpoint divide slice into two fn foo(vec: &mut [T]) { let (less, greater) = vec.split_at_mut(3); … } `vec` borrowed here while `less` and `greater` still in use
  • 35. 35 Parallelism Photo credit: Dave Gingrich https://www.flickr.com/photos/ndanger/2744507570/
  • 36. 36 Observation: Building parallel abstractions is easy. Misusing those abstractions is also easy. func foo(…) { m := make(map[string]string) m[“Hello”] = “World” channel <- m m[“Hello”] = “Data Race” } send data over channel but how to stop sender from
 using it afterwards? GoCode
  • 37. 37 fn foo(…) { let m = HashMap::new(); m.insert(“Hello”, “World”); channel.send(m); m.insert(“Hello”, “Data Race”); } impl<T> Channel<T> { fn send(&mut self, data: T) { … } } Take ownership of the data Error: use of moved value: `book` ~~~~~~~~~~~~~~~~~~~~~~~~~~
  • 38. ~ Concurrency paradigms ~ Paradigm Message passing Ownership? Borrowing? ✓ Locking ✓ ✓
  • 39. 0 fn sync_inc(mutex: &Mutex<i32>) { let mut guard: Guard<i32> = counter.lock(); *guard += 1; } https://commons.wikimedia.org/wiki/File:No-DRM_lock.svg 1 mutex guard
  • 40. ~ Concurrency paradigms ~ Paradigm Message passing Ownership? Borrowing? ✓ Locking ✓ ✓ Fork join ✓
  • 41. 41 fn divide_and_conquer(…) { rayon::join( || do_something(), || do_something_else(), ); } Conceptually: - Start two threads - Wait for them to finish
  • 42. [0] [1] [2] [3] […] [n] vec: &mut [i32] less: &mut [i32] greater: &mut [i32] 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); qsort(less); qsort(greater); }
  • 43. 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] rayon::join( || qsort(less), || qsort(less), ); ?~~~~~~~~~
  • 44. ~ Concurrency paradigms ~ Paradigm Message passing Ownership? Borrowing? ✓ Locking Fork join ✓ ✓ ✓ Lock-free Futures … ✓ ✓ ✓ ✓
  • 46. 46 Vision: An Extensible Language Core language: Ownership and borrowing Libraries: Reference-counting Files Parallel execution … Use ownership/ borrowing to enforce correct usage. ]
  • 47. Safe abstractions unsafe { … } Ownership/borrowing/traits give tools to enforce safe abstraction boundaries. Trust me. fn split_at_mut(…) { } Validates input, etc. 47
  • 48. 48 Stylo (Parallel CSS Rendering — coming in FF57) Total KLOC Unsafe KLOC Unsafe % Total 146.2 51.7 35% Interesting stuff 71.6 1.4 1.9% FFI Bindings 74.5 50.3 67.4%
  • 49. 49
  • 50. 50
  • 51. 51
  • 52. 52 Photo credit: Salim Virji https://www.flickr.com/photos/salim/8594532469/ Safety = Eat your spinach!
  • 53. 53 0 25 50 75 100 Amazon YouTube YouTube (32 bit) Initial load times (relative to today) Amdahl’s Line Page Layo ut O ther stuff
  • 55. 55 Community Photo credit: David McSpadden https://www.flickr.com/photos/familyclan/15535822737/
  • 56. 56 Rust Leadership Structure Team Members Peers Core 9 Language 6 5 Libraries 7 1 Compiler 9 Dev Tools 6 11 Cargo 6 Infrastructure 10 Community 13 Documentation 4 Moderation 5 58 people 10 Mozilla (17%)
  • 57. 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
  • 60. 60 Want to learn more? intorust.comrust-lang.orgO’Reilly Book, 2nd ed. ScreencastsPre-order now!