Rust for $LANGUAGE-ists

By Steve Klabnik

Slides: http://steveklabnik.github.io/nobody_knows_rust/

About the
language

Rust!!!!!!111

Rust is a really interesting new programming language.

Rust is a good choice when you'd choose C++. And maybe other times.

"Rust is a systems language pursuing the trifecta:
safe, concurrent, and fast."

Rust is an ownership-oriented programming language.

Origins

Rust was written by Graydon Hoare. Mozilla has taken stewardship.

Mozilla writes lots of C++, and feels that pain.

Stability

Rust is currently at version 0.10.

Snapshots, not backwards compatible.

1.0 is coming soon.

Some code

Segfaults


int main(void)
{
     char *s = "hello world";
     *s = 'H';
}

Segfaults


fn main() {
    let s = &"hello world";
    *s = "H";
}

segfault.rs:3:4: 3:6 error: type &str cannot be dereferenced
segfault.rs:3     *s = "H";
                  ^~
error: aborting due to previous error
task 'rustc' failed at 'explicit failure', ...

Hello world


use std::io::println;

fn main() {
  println("Hello, world");
}

A little more complex


fn main() {
    let nums = [1, 2];
    let noms = ["Tim", "Eston", "Aaron", "Ben"];
 
    let mut odds = nums.iter().map(|&x| x * 2 - 1);
 
    for num in odds {
        spawn(proc() {
            println!("{:s} says hello from a lightweight thread!", noms[num]);
        });
    }
}

References


fn plus_one(x: &int) -> int {
    *x + 1
}

fn main() {
    println!("{}", plus_one(&5));
}

Boxes


fn plus_one(x: &int) -> int {
    *x + 1
}

fn main() {
    let x = ~5;
    println!("{}", plus_one(x));
}

Tasks


fn main() {
    let (chan, port) = channel();

    spawn(proc() {
        let result = 5;
        chan.send(result);
    });

    let result = port.recv();
    println!("{:d}", result);
}

Tasks & safety


fn main() {
    let (chan, port) = channel();
    let x = ~5;

    spawn(proc() {
        let result = 5 + *x;
        chan.send(result);
    });

    let result = port.recv();
    println!("{:d}", result);
}

Tasks & safety


fn main() {
    let (chan, port) = channel();
    let x = ~5;

    spawn(proc() {
        let result = 5 + *x;
        chan.send(result);
    });

    *x += 1;

    let result = port.recv();
    println!("{:d}", result);
}

Tasks & safety


segfault.rs:10:5: 10:6 error: use of moved value: `x`
segfault.rs:10     *x += 1;
                    ^
segfault.rs:5:7: 8:5 note: `x` moved into closure
environment here because it has type `proc:Send()`,
which is non-copyable (perhaps you meant to use clone()?)
segfault.rs:5     do spawn || {
segfault.rs:6         let result = 5 + *x;
segfault.rs:7         chan.send(result);
segfault.rs:8     }
segfault.rs:10:4: 10:6 error: cannot assign to immutable dereference of ~ pointer
segfault.rs:10     *x += 1;
                   ^~
error: aborting due to 2 previous errors

Pattern Matching


match my_number {
  0     => println("zero"),
  1 | 2 => println("one or two"),
  3..10 => println("three to ten"),
  _     => println("something else")
}

Option and
pattern matching


let msg = Some(~"howdy");

// Take a reference to the contained string
match msg {
    Some(ref m) => io::println(*m),
    None => ()
}

Closures


let square = |x: int| -> uint { (x * x) as uint };

let mut max = 0;
[1, 2, 3].map(|x| if *x > max { max = *x });

Generics


fn map<T, U>(vector: &[T], function: |v: &T| -> U) -> ~[U] {
    let mut accumulator = ~[];
    for element in vector.iter() {
        accumulator.push(function(element));
    }
    return accumulator;
}

Structs and traits


struct TimeBomb {
    explosivity: uint
}

impl Drop for TimeBomb {
    fn drop(&mut self) {
        for _ in range(0, self.explosivity) {
            println("blam!");
        }
    }
}

Traits and
parameterization


trait Seq<T> {
    fn length(&self) -> uint;
}

impl<T> Seq<T> for ~[T] {
    fn length(&self) -> uint { self.len() }
}

More Traits


extern mod active_support;
use active_support::Period;
use active_support::Time;

fn main() {
  let time = Time::now();
  println!("{:?}", time);
  println!("{:?}", 2.days().from_now());
  println!("{:?}", 2.weeks().from_now());
  println!("{:?}", 2.months().from_now());
  println!("{:?}", 2.years().from_now());
}

More Traits


use TimeChange;

pub trait Period {
  fn seconds(&self) -> TimeChange;
  fn minutes(&self) -> TimeChange;
  // ...
}

impl Period for uint {
  fn seconds(&self) -> TimeChange {
    TimeChange::new().seconds(*self as f32)
  }

  fn minutes(&self) -> TimeChange {
    TimeChange::new().minutes(*self as f32)
  }

  // ...
}

FFI


use std::libc::size_t;

#[link(name = "snappy")]
extern {
    fn snappy_max_compressed_length(source_length: size_t) -> size_t;
}

fn main() {
    let x = unsafe { snappy_max_compressed_length(100) };
    println!("max compressed length of a 100 byte buffer: {}", x);
}

FFI


pub fn validate_compressed_buffer(src: &[u8]) -> bool {
    unsafe {
        snappy_validate_compressed_buffer(src.as_ptr(), src.len() as size_t) == 0
    }
}

FFI


pub fn uncompress(src: &[u8]) -> Option<~[u8]> {
    unsafe {
        let srclen = src.len() as size_t;
        let psrc = src.as_ptr();

        let mut dstlen: size_t = 0;
        snappy_uncompressed_length(psrc, srclen, &mut dstlen);

        let mut dst = vec::with_capacity(dstlen as uint);
        let pdst = dst.as_mut_ptr();

        if snappy_uncompress(psrc, srclen, pdst, &mut dstlen) == 0 {
            dst.set_len(dstlen as uint);
            Some(dst)
        } else {
            None // SNAPPY_INVALID_INPUT
        }
    }
}

Learning more

Awesome projects

  • charliesome/rustboot
  • chris-morgan/rust-http
  • thestinger/rust-core
  • pcwalton/sprocketnes
  • williamw520/rustymem
  • mneumann/{rust-redis,rust-msgpack}
  • lifthrasiir/angolmois-rust

Introductions

  • The official tutorial
  • Rust for Rubyists
  • Rust Tutorials_NG

Discussion Fora

  • The rust-dev mailing list
  • /r/rust
  • #rust on irc.mozilla.org
  • This Week in Rust

Code

https://github.com/mozilla/rust

Thank you! <3

@steveklabnik