Jan-Erik / @badboy_
04.03.2015 / cccac
$ ./awesome-prog
…
segmentation fault (core dumped) ./awesome-prog
* In theory. Rust is a work-in-progress and may do anything it likes up to and including eating your laundry.
* In theory. Rust is a work-in-progress and may do anything it likes up to and including eating your laundry.
Compiled binary
Based on LLVM, including optimizations
Competitive with C/C++
Static Analysis at compile time
Borrow Checker captures most issues
(more on that later)
Why is there no compiler flag to eliminate array bounds checks?
(answer: because bstrie would fork the language and make the flag delete your hard drive)
Type system and analysis
No segfaults
No null pointers
No dangling pointers
Ownership: data has one owner
Borrowing: you can hand it over
Everything is safe
Only ever one owner of data
Variables are moved
Previous location cannot use it anymore
fn helper(slot: Box<u32>) { /* … */ } fn main() { let slot = Box::new(3); helper(slot); helper(slot); }
fn helper(slot: Box<u32>) { /* … */ } fn main() { let slot = Box::new(3); helper(slot); helper(slot); }
$ rustc owner-helper.rs
owner-helper.rs:6:12: 6:16 error: use of moved value: `slot`
owner-helper.rs:6 helper(slot);
^~~~
owner-helper.rs:5:12: 5:16 note: `slot` moved here because it has type `Box<u32>`, which is non-copyable
owner-helper.rs:5 helper(slot);
^~~~
error: aborting due to previous error
It avoids garbage collecting, refcounting, and manual memory management.
* alexchandel on What's Your Killer Rust Feature?
Hand over access for a period of time
fn helper(slot: &Vec<u32>) { /* … */ } fn main() { let a = Vec::new(); helper(&a); helper(&a); }
Borrowing prevents moving
fn work_with(slot: Vec<u32>) { /* … */ } fn main() { let a = Vec::new(); let b = &a; work_with(a); // error! }
borrow.rs:9:15: 9:16 error: cannot move out of `a` because it is borrowed
borrow.rs:9 work_with(a); // error!
^
borrow.rs:6:18: 6:19 note: borrow of `a` occurs here
borrow.rs:6 let b = &a;
Borrowed values are valid for a lifetime
fn work_with(slot: Vec<u32>) { /* … */ } fn main() { let a = Vec::new(); { let b = &a; } work_with(a); // ok }
v = []
v.push("Hello")
x = v[0]
v.push("world")
puts x
$ ruby hello.rb Hello
* taken from Steve Klabnik's FOSDEM talk
#include <iostream>
#include <vector>
#include <string>
int main() {
std::vector<std::string> v;
v.push_back("Hello");
std::string& x = v[0];
v.push_back("world");
std::cout << x;
}
$ g++ ownership.cpp -Wall -Werror
$ ./a.out
Segmentation fault (core dumped)
If the new size() is greater than capacity() then all iterators and references (including the past-the-end iterator) are invalidated.
* from cppreference.com
fn main() { let mut v = vec![]; v.push("Hello"); let x = &v[0]; v.push("world"); println!("{}", x); }
$ rustc ownership.rs
ownership.rs:8:5: 8:6 error: cannot borrow `v` as mutable because it is also borrowed as immutable
ownership.rs:8 v.push("world");
^
ownership.rs:6:14: 6:15 note: previous borrow of `v` occurs here; the immutable borrow prevents subsequent moves or mutable borrows of `v` until the borrow ends
ownership.rs:6 let x = &v[0];
^
ownership.rs:11:2: 11:2 note: previous borrow ends here
ownership.rs:1 fn main() {
...
ownership.rs:11 }
^
error: aborting due to previous error
Resource Acquisition Is Initialization
Rust Means Never Having to Close a Socket
fn main() { // Create lots of boxes for i in 0..1_000 { let boxed_int = Box::new(i); } }
fn main() { // Create lots of boxes for i in 0..1_000 { let boxed_int = Box::new(i); } }
$ rustc raii.rs
$ valgrind ./raii
…
==3578== HEAP SUMMARY:
==3578== in use at exit: 0 bytes in 0 blocks
struct Object { boxed: u32 } impl Drop for Object { fn drop(&mut self) { println!("Dropping myself. boxed={}", self.boxed); } } fn main() { let obj = Object { boxed: 42 }; println!("End of program"); }
struct Object { boxed: u32 } impl Drop for Object { fn drop(&mut self) { println!("Dropping myself. boxed={}", self.boxed); } } fn main() { let obj = Object { boxed: 42 }; println!("End of program"); }
$ rustc raii-drop.rs
$ ./raii-drop.rs
End of program
Dropping myself. boxed=42
use std::thread; fn main() { let mut a = Vec::new(); let _ = thread::spawn(move|| { a.push("foo"); }); a.push("bar"); }
$ rustc conc.rs
conc.rs:10:5: 10:6 error: use of moved value: `a`
conc.rs:10 a.push("bar");
^
conc.rs:6:31: 8:6 note: `a` moved into closure environment here because it has type `[closure(())]`, which is non-copyable
use std::thread; use std::sync::{Arc, Mutex}; fn main() { let numbers = Arc::new(Mutex::new(vec![1, 2, 3])); for i in 0..3 { let number = numbers.clone(); let _ = thread::scoped(|| { let mut array = number.lock().unwrap(); array[i] += 1; println!("numbers[{}] is {}", i, array[i]); }); } }
extern crate threadpool; use threadpool::ScopedPool; fn main() { let mut numbers: &mut [u32] = &mut [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; // We need an extra scope to shorten the lifetime of the pool { let pool = ScopedPool::new(4); for x in &mut numbers[..] { pool.execute(move|| { *x *= 2; }); } } println!("{:?}", numbers); }
fn main() { let a = 3; unsafe { let b = &a as *const u32 as *mut u32; *b = 4; } println!("{}", a); }
$ rustc unsafe.rs
$ ./unsafe
4
* only a few, there are far more
* Ferris the crab, the unofficial mascot for Rust, www.rustacean.net