Programmation système robuste avec Rust

Le duo comique

Programmation système

le CPU, zone de non-droit

Pourquoi un langage bas-niveau ?

Les langages Old School

Aucune assurance

Y a pas de bug dans mon code

Program received signal SIGSEGV, Segmentation fault.
0x1c0007a8 in main () at main.c:6

Rust

Buts du langage

Memory safe

    Do not kill bugs, kill bug classes

Un monde sans GC ?

3 méthodes de stockage de données:

Statique

fn main() {
  println!("hello world");
}

Stack

fn f() -> &uint {
  let s = 1;
  let r = &s;
  r
}
fn main() {
  println!("{}", f());
}
static.rs:3:11: 3:13 error: `s` does not live long enough
static.rs:3   let r = &s;

Stack: l'erreur complète

static.rs:3:11: 3:13 error: `s` does not live long enough
static.rs:3   let r = &s;
                      ^~
static.rs:1:17: 5:2 note: reference must be valid for the
anonymous lifetime #1 defined on the block at 1:16...
static.rs:1 fn f() -> &uint {
static.rs:2   let s = 1;
static.rs:3   let r = &s;
static.rs:4   r
static.rs:5 }
static.rs:1:17: 5:2 note: ...but borrowed value is only
valid for the block at 1:16
static.rs:1 fn f() -> &uint {
static.rs:2   let s = 1;
static.rs:3   let r = &s;
static.rs:4   r
static.rs:5 }
error: aborting due to previous error

Heap

fn f() -> ~str {
  let s = ~"hello world";
  s
}
fn main() {
  println!("{}", f());
}

Ownership

fn main() {
  let s = ~"hello world";
  spawn(proc() {
    println!("other task: {}", s);
  });
  println!("main task {}", s);
}
borrow.rs:6:28: 6:29 error: use of moved value: `s`
borrow.rs:6   println!("main task {}", s);
                                       ^
[...]
borrow.rs:3:9: 5:4 note: `s` moved into closure environment
here because it has type `proc:Send()`,which is non-copyable
(perhaps you meant to use clone()?)
borrow.rs:3   spawn(proc() {
borrow.rs:4     println!("other task: {}", s);
borrow.rs:5   });

Ca peut être unsafe

use std::cast;
let mut x: u8 = 1;

let ref_1: &mut u8 = &mut x;
let ref_2: &mut u8 = unsafe {
  cast::transmute_mut_region(ref_1)
};

// ref_1 et ref_2 pointent vers la même zone mémoire
*ref_1 = 10;
*ref_2 = 20;

On peut écrire de l'assembleur

fn add(a: int, b: int) -> int {
  let mut c = 0;
  unsafe {
    asm!("add $2, $0"
         : "=r"(c)
         : "0"(a), "r"(b)
         );
  }
  c
}

GC

Ca existe, mais...

Que propose Rust?

Concurrence

Concurrence

Lancer une task

fn print_message() { println!("Hello!"); }
spawn(print_message);

Channels

let (tx, rx): (Sender<int>, Receiver<int>) = channel();

spawn(proc() {
  let result = 1;
  tx.send(result);
  println!("result sent");
});

sleep(200);
let result = rx.recv();
println!("result: {}", result);

Ownership

let (tx, rx) = channel();

for init_val in range(0u, 3) {
  let child_tx = tx.clone();
  spawn(proc() {
    child_tx.send(init_val);
    sleep(1000 - (init_val as u64) * 100);
    println!("sent computation result: {}", init_val);
  });
}

let result = rx.recv() + rx.recv() + rx.recv();
println!("result: {}", result);

Futures

  let mut future = sync::Future::spawn( proc() {
    partial_sum(ind)
  });

  sleep(200);
  println!("result: {}", ft.get());

Patterns

Let it crash

Let it crash

Type-Directed Development

Mutabilité par défaut == optimisation prématurée

L’immutabilité

Système de types

Système de types

Aller plus loin

Structures de données


pub struct Point {
    pub x: int,
    pub y: int
}

pub struct Circle {
    pub center: ~Point,
    pub radius: uint
}

Structures de données


pub enum Json {
    Number(f64),
    String(~str),
    Boolean(bool),
    List(List),
    Object(~Object),
    Null,
}

pub type List = ~[Json];
pub type Object = TreeMap<~str, Json>;

Pattern matching


match jsonValue {
    Number(n) => ...
    String(s) => ...
    ...
}

Traits

impl Circle {
    pub fn radius(&self) -> f64 {
        f64::consts::PI * self.radius * 2
    }
}

Typeclass pattern


pub trait Show {
    fn fmt(&self, &mut Formatter) -> Result;
}
impl fmt::Show for Circle {
    fn show(&self, fmt: &mut ftm::Formatter) -> float {
        write!(fmt.buf, ...)
    }
}

Traits de base

Auto implémetation


#[deriving(Eq, Clone, Show)]
pub struct Point {
    pub x: f64,
    pub y: f64
}

#[deriving(Eq, Clone, Show)]
pub struct Circle {
    pub center: ~Point,
    pub radius: f64
}

Polymorphisme paramétrique

pub enum Option<T> {
    None,
    Some(T)
}

Polymorphisme paramétrique + traits

Typeclass pattern

impl<A:ToJson> ToJson for Option<A> {
    fn to_json(&self) -> Json {
        match *self {
          None => Null,
          Some(ref value) => value.to_json()
        }
    }
}

Crates, modules, etc

Crates, modules, etc