Presentation for the Frostbite Rendering Team (+ Friends!) by Daniel Collin / @daniel_collin
To Alex Crichton (of Mozilla Research) for allowing me to use some of his slides in this presentation.
Me and programming languages.
Aiming to try out 3 new programming languages every year.
See beyond the usual box.
Ideas, concepts can usually be applied in your "daily" language as well.
Spend more time with the ones I find most interesting.
fn main() {
  println!("hello, {}", "world!");
}
        Rust grew out of a personal project by Mozilla employee Graydon Hoare.
Mozilla sponsored starting in 2009. Rust itself is community driven under MIT licence.
| C/C++ | Java/.NET | Python | |
| More control, less safety | Less control, more safety | ||
More control, more safety
Type system enforces ownership and borrowing
int main() {
    int* data = malloc(sizeof(int));
    *data = 3;
    foo(slot);
    foo(slot); // use after free!
}
void foo(int* data) {
    printf("The number was: %d\n", *data);
    free(data);
}
							
a.out(62940,0x7fff7b9ea310) malloc: *** error for object 0x7fecb0c03b10:
pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
zsh: abort      ./a.out
					
fn main() {
    let data = Box::new(3u32);
    foo(data); // moves the value!
    foo(data); // error: use of moved value
}
fn foo(slot: Box<u32>) {
    println!("The number was: {}", slot);
}
        
test.rs:6:9: 6:13 error: use of moved value: `data` [E0382]
test.rs:6     foo(data); // error: use of moved value
                 ^~~~
test.rs:5:9: 5:13 note: `data` moved here because it has type 'Box<u32>', 
                         which is non-copyable
test.rs:5     foo(data); // moves the value!
                 ^~~~
error: aborting due to previous error
fn foo() -> Box<u32> {
    let three = Box::new(3u32);
    return three; // transfer ownership
}
fn main() {
    // acquire ownership of return value
    let my_three = foo();
}
						Owned values can be borrowed in Rust to allow usage for a certain period of time.
// The `&` sigil means "borrowed reference"
fn foo(slot: &Vec<u32>) { /* ... */ }
fn main() {
    let data = Vec::new();
    // doesn't move!
    foo(&data);
    foo(&data);
}
        Borrowed values are only valid for a particular lifetime
let a: &u32;
{
    let b = 3;
    a = &b; // error! `b` does not live long enough
}
        
let b = 3;
let a: &u32;
a = &b; // ok, `b` has the same lifetime as `a`
        Borrowing prevents moving
let a = Vec::new();
let b = &a;
work_with(a); // error!
        
let a = Vec::new();
{
    let b = &a;
}
work_with(a); // ok
        
fn main() {
    println!("Your number was: {}", *foo());
}
// Tries to return borrowed reference to `a`
fn foo() -> &u32 {
    let a = 3u32;
    return &a;
}
        Borrows can be nested
struct MyStruct { inner: u32 }
fn get(s: &MyStruct) -> &u32 {
    &s.inner
}
fn main() {
    let s = MyStruct { inner: 3u32 };
    let inner = get(&s); // same lifetime as `s`
}
        Borrowed values can become owned values through cloning
fn clone_vector(v: &Vec<u32>) -> Vec<u32> {
    v.clone()
}
        Rust has fine-grained memory management, but is automatically managed once created.
Each variable has a scope it is valid for, and it is automatically deallocated when it goes out of scope.
fn main() {
    // main owns 'data'
    let data = Box::new(4u32);
    // The data goes out of scope, it is free'd
}
        Also possible to explicitly free data using drop
fn main() {
    // main owns 'data'
    let data = Box::new(4u32);
    // Do something with data here..
    // ...
    // Now free data
    drop(data);
    // Compile error if we try to use data 
    println!("Trying to use data {}", data);
}
        Reference counting is another way of managing memory.
use std::rc::Rc;
fn main() {
    let data = Rc::new(3u32); // reference count of 1
    {
        let data2 = data.clone(); // reference count of 2
        use_data(data2); // transfer ownership of `data2`
    } // reference count of 1
    use_data(data); // transfer ownership of `data`
} // reference count of 0, memory deallocated
fn use_data(data: Rc<u32>) {}
        Values are immutable by default in Rust, and must be tagged as being mutable.
let a = 4;
a = 5; // error!
        
let mut a = 4;
a = 5; // ok
        Mutability is also a part of the type of a borrowed pointer.
fn inc(i: &i32) {
    *i += 1; // error!
}
        
fn inc(i: &mut i32) {
    *i += 1; // ok
}
        Borrowed pointers may coerce
let a = &mut 1;
let b: &i32 = a; // ok
let c: &mut i32 = b; // error!
        Values can be frozen by borrowing
let mut a = Vec::new();
{
    let b = &a; // freezes `a`
    a.push(1);  // error!
}
a.push(2); // ok
        Mutability propagates deeply into owned types
struct A { b: B }
struct B { c: i32 }
fn main() {
    let mut a = A { b: B { c: 2 } };
    a.b.c = 3;
    a.b = B { c: 4 };
    a = A { b: B { c: 5 } };
    let frozen = a;
    frozen.b.c = 4; // error!
}
        Using ownership to prevent data races.
Parallelism is achieved at the granularity of an OS thread but it's also possible to use libraries like threadpool.
// Spawn a child thread to be run in parallel
spawn(move || {
    expensive_computation();
});
other_expensive_computation();
        Safety is achieve by requiring spawn to use 'move' closure to capture variables.
use std::thread;
fn main() {
    let mut a = Vec::new();
    thread::spawn(move || {
        a.push("foo");
    });
    a.push("bar"); // error!
}
        Threads can communicate with channels
let (tx, rx) = channel();
spawn(move || {
    tx.send(expensive_computation());
});
// Do some work in the meantime
let answer = rx.recv();
        Tasks can also share memory
use std::collections::HashMap;
use std::sync::Arc;
use std::thread;
fn main() {
    let mut map = HashMap::new();
    map.insert("tomato", "red");
    map.insert("celery", "green");
    map.insert("carrot", "orange");
    let arc1 = Arc::new(map);
    let arc2 = arc1.clone();
    spawn(move || println!("Celery is `{}`", arc1["celery"]));
    spawn(move || println!("Carrots are `{}`", arc2["carrot"]));
}
        Using a Mutex it's possible to modify shared state
use std::sync::{Arc, Mutex};
use std::thread;
// Mutex is design so it be owner of a piece of data and
// use borrowing to lend it to others 
fn main() {
    let data = Arc::new(Mutex::new(4u32));
    for _ in 0..10 {
       let thread_data = data.clone();
       thread::spawn(move || {
           let mut data = thread_data.lock().unwrap();
           *data += 1;
        });
    }
}
     
struct Point {
    x: f32,
    y: f32,
}
fn main() {
    let p = Point { x: 1.0, y: 2.0 };
}
        
fn main() {
  let number = 13;
  println!("Tell me about {}", number);
  match number {
    // Match a single value
    1 => println!("One!"),
    // Match several values
    2 | 3 | 5 | 7 | 11 => println!("This is a prime"),
    // Match an inclusive range
    13...17 => println!("A teen"),
    // Handle the rest of cases
    _ => println!("Ain't special"),
  }
}
        
enum Shape {
    Circle,
    Square
}
fn test(shape: Shape) {
    match shape {
        Circle => { /* ... */ }
        Square => { /* ... */ }
    }
}
        Enums can have data. This is compiled into a union + tag
enum Shape {
    Circle(Point, f64),
    Rectangle(Point, Point),
}
match shape {
    Circle(center, radius) => {
        draw_circle(center, radius)
    }
    Rectangle(ul, lr) => {
        draw_rectangle(ul, lr)
    }
}
        
trait Hello {
    fn hello(&self);
}
        
impl Hello for Point {
    fn hello(&self) {
        println!("Hello!");
    }
}
        Traits can also be applied on existing types
trait Hello {
    fn hello(&self);
}
impl Hello for u32 {
    fn hello(&self) {
        println!("Hello!");
    }
}
fn main() {
    4u32.hello(); // Considered bad style!
}
        Rust has modules to split code in logical units
fn function() {
    println!("Called 'function'");
}
mod my {
    pub fn function() {
        println!("Called 'my::function'");
    }
}
fn main() {
    function();
    my::function();
}
        
fn main() {
    let a = 3;
    // Turn off some compiler checks,
    // "I know what I'm doing"
    unsafe {
        let b = &a as *const i32 as *mut i32;
        *b = 4;
    }
    println!("{}", a); // prints 4
}
        Transform one type to another
unsafe fn transmute<T, U>(t: T) -> U {
    /* ... */
}
        
// Invalid promotion to a mutable pointer
let a: &int = &3;
let b: &mut int = unsafe { transmute(a) };
    
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
fn foo() {
    unsafe {
        asm!("nop");
    }
}
    
extern {
    fn write(fd: i32, data: *const u8, len: u32) -> i32;
}
fn main() {
    let data = b"Hello, world!\n";
    unsafe {
        write(1, &data[0], data.len() as u32);
    }
}
		
_ZN4main20h9abc3392beeae1c4saaE:
	.cfi_startproc
	leaq	byte_str2755(%rip), %rsi
	movl	$1, %edi
	movl	$14, %edx
	jmp	write@PLT
     Defining a Cargo.toml file for a project.
[package]
name = "hello_world"
version = "0.1.0"
authors = ["Your Name you@example.com"]
[dependencies]
regex = "0.1.41"
     
extern crate regex;
use regex::Regex;
fn main() {
    let re = Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap();
    println!("Did our date match? {}", re.is_match("2014-01-01"));
}
     
$ cargo build
    Updating registry `https://github.com/rust-lang/crates.io-index`
 Downloading memchr v0.1.5
 Downloading libc v0.1.10
 Downloading regex-synatx v0.2.1
 Downloading memchr v0.1.5
 Downloading aho-corasick v0.3.0
 Downloading regex v0.1.41
   Compiling memchr v0.1.5
   Compiling libc v0.1.10
   Compiling regex-synatx v0.2.1
   Compiling memchr v0.1.5
   Compiling aho-corasick v0.3.0
   Compiling regex v0.1.41
   Compiling foo v0.1.0 (file:///path/to/project/hello_world)
    Easy to test code. Lets say we have a project called adder
#[test]
fn it_works() {
}
    
$ cargo test
   Compiling adder v0.0.1 (file:///home/you/projects/adder)
     Running target/adder-91b3e234d4ed382a
running 1 test
test it_works ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
   Doc-tests adder
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
    Learning @rustlang: Borrow checker -> borrow checker -> borrow checker -> borrow checker -> understanding -> productivity -> happiness.
— Lori Holden (@lholden) September 8, 2015