Rust for Rubyists

(and others)

By Steve Klabnik

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

Why Rust?

"I don't need to worry about
performance. If I do,
I can just drop into C."


$ cat hello.rb 
puts "Hello, world."

steve@computer:~/tmp$ time ruby hello.rb
Hello, world.

real  0m0.037s
user  0m0.031s
sys 0m0.007s

steve@computer:~/tmp$ cat hello.rs
use std::io::println;

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

steve@computer:~/tmp$ time ./hello
Hello, world.

real  0m0.004s
user  0m0.001s
sys 0m0.002s

How do you eat a Monorail?
One bite at a time.

I am not the only Rubyist
interested in Rust.

TL;DR

"Rust provides the safety and
conveninence of Ruby with the speed of native code." - wycats (ish)

Let's see some code!


fn main() {
    let nums = [1, 2];
    let noms = ["Steve", "Matz", "Aaron", "David"];

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

fn main() {
  // A simple integer calculator:
  // `+` or `-` means add/sub by 1
  // `*` or `/` means mul/div by 2
 
  let program = "+ + * - /";
  let mut accumulator = 0;
 
  for token in program.chars() {
    match token {
      '+' => accumulator += 1,
      '-' => accumulator -= 1,
      '*' => accumulator *= 2,
      '/' => accumulator /= 2,
      _ => { /* ignore everything else */ }
    }
  }
 
  println!("The program \"{}\" calculates the value {}",
       program, accumulator);
}


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

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

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

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

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

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

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

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

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

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

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

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

    *x += 1;

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

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

shell returned 101


fn main() {
    let x: int;
    println!("{}", x);
}

hello.rs:3:20: 3:21 error: use of possibly uninitialized variable: `x`
hello.rs:3     println!("{}", x);
                              ^

fn foo() -> Box<str> {
    box "a boxed string"
}

fn bar() -> Option<Box<str>> {
    Some(box "a boxed string")
}

fn main() {
    let msg = bar();

    match msg {
        Some(ref m) => std::io::println(*m),
        None => ()
    }
}

fn foo() -> Box<str> {
    box "a boxed string"
}

fn bar() -> Option<Box<str>> {
    Some(box "a boxed string")
}


struct TimeBomb {
    explosivity: uint
}

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


trait Printable {
    fn print(&self);
}

impl Printable for TimeBomb {
    fn print(&self) { println!("My counter is:{}", self.explosivity) }
}

let x = TimeBomb { explosivity: 5 };

x.print();


//fail
fn print_all(printable_things: Vec<T>) {
    for thing in printable_things.iter() {
        thing.print();
    }
}

//succeed
fn print_all<T: Printable>(printable_things: Vec<T>) {
    for thing in printable_things.iter() {
        thing.print();
    }
}

impl Printable for int {
    fn print(&self) { println!("{}", *self) }
}

5.print();

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

Cargo!


[package]

name = "edges"
version = "0.1.0"
authors = [ "steve@steveklabnik.com" ]

[dependencies.hamcrest]

git = "https://github.com/carllerche/hamcrest-rust.git"

Yeah, but what about production?

Rust is not yet 1.0

Three known production deployments

Stable...ish

Communicating about stability

1.0 this year

Learning more

Introductions

  • The official Guide
  • Rust for Rubyists
  • Rust by Example

Discussion Fora

  • The rust-dev mailing list
  • /r/rust
  • #rust on irc.mozilla.org

Code

https://github.com/mozilla/rust

Thank you! <3

@steveklabnik