Rust

Jan-Erik / @badboy_

04.03.2015 / cccac

 

$ ./awesome-prog

…

segmentation fault (core dumped)  ./awesome-prog

Rust

What is Rust?

Rust is a systems programming language that runs blazingly fast, prevents almost all crashes*, and eliminates data races.

* In theory. Rust is a work-in-progress and may do anything it likes up to and including eating your laundry.

What is Rust?

Rust is a systems programming language that runs blazingly fast, prevents almost all crashes*, and eliminates data races.

* In theory. Rust is a work-in-progress and may do anything it likes up to and including eating your laundry.

Blazingly fast

Zero Cost Abstractions

Zero Cost Abstractions (mostly)

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)

Prevents almost all crashes

Eliminates data races

Ownership system

Ownership

fn helper(slot: Box<u32>) { /* … */ }

fn main() {
    let slot = Box::new(3);
    helper(slot);
    helper(slot);
}

Ownership

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

Killer Feature: Borrow Checker

It avoids garbage collecting, refcounting, and manual memory management.

* alexchandel on What's Your Killer Rust Feature?

Borrowing

Hand over access for a period of time

fn helper(slot: &Vec<u32>) { /* … */ }

fn main() {
    let a = Vec::new();

    helper(&a);
    helper(&a);
}

Borrowing

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;

Borrowing

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
}

Ownership & Borrowing combined

v = []

v.push("Hello")

x = v[0]

v.push("world")

puts x

$ ruby hello.rb
Hello

* taken from Steve Klabnik's FOSDEM talk

Ownership & Borrowing combined

#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;
}

Ownership & Borrowing combined

$ g++ ownership.cpp -Wall -Werror
$ ./a.out
Segmentation fault (core dumped)

Ownership & Borrowing combined

If the new size() is greater than capacity() then all iterators and references (including the past-the-end iterator) are invalidated.

* from cppreference.com

Ownership & Borrowing combined

fn main() {
    let mut v = vec![];

    v.push("Hello");

    let x = &v[0];

    v.push("world");

    println!("{}", x);
}

Ownership & Borrowing combined

$ 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

Memory Management

Resource Acquisition Is Initialization

or:

Rust Means Never Having to Close a Socket

Memory Management

fn main() {
    // Create lots of boxes
    for i in 0..1_000 {
        let boxed_int = Box::new(i);
    }
}

Memory Management

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

Memory Management - Drop Trait

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");
}

Memory Management - Drop Trait

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

Concurrency

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

Concurrency

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]);
        });
    }
}

Concurrency

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);
}

Unsafe code

fn main() {
    let a = 3;

    unsafe {
        let b = &a as *const u32 as *mut u32;
        *b = 4;
    }

    println!("{}", a);
}
$ rustc unsafe.rs
$ ./unsafe
4

More, more, more

More, more, more

More, more, more

More, more, more

More, more, more

More, more, more

More, more, more

More, more, more

More, more, more

More, more, more

More, more, more

More, more, more

More, more, more

The Releases

Projects

Projects: Servo

Projects: Firefox Integration

Projects: misc

* only a few, there are far more

In Production

That's it!

www.rust-lang.org

* Ferris the crab, the unofficial mascot for Rust, www.rustacean.net

otsconf

www.otsconf.com

Sources