Why Rust? – About thelanguage – Some code



Why Rust? – About thelanguage – Some code

1 5


nobody_knows_rust


On Github steveklabnik / nobody_knows_rust

Why Rust?

By Steve Klabnik

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

About thelanguage

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 1.0

New versions every six weeks!

Backwards compatible

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

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

A little more complex

use std::thread;

fn main() {
    let nums = [1, 2];
    let noms = ["Tim", "Eston", "Aaron", "Ben"];

    let odds = nums.iter().map(|&x| x * 2 - 1);

    for num in odds {
        thread::spawn(move || {
            println!("{} says hello from a thread!", noms[num]);
        });
    }

    thread::sleep_ms(100);
}

References

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

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

Boxes

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

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

Threads

use std::sync::mpsc;
use std::thread;

fn main() {
    let (tx, rx) = mpsc::channel();

    thread::spawn(move || {
        let result = 5;
        tx.send(result);
    });

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

Threads & safety

use std::sync::mpsc;
use std::thread;

fn main() {
    let (tx, rx) = mpsc::channel();
    let x = Box::new(5);

    thread::spawn(move || {
        let result = 5 + *x;
        tx.send(result);
    });

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

Threads & safety

use std::sync::mpsc;
use std::thread;

fn main() {
    let (tx, rx) = mpsc::channel();
    let x = Box::new(5);

    thread::spawn(move || {
        let result = 5 + *x;
        tx.send(result);
    });

    *x += 5;

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

Threads & safety

hello.rs:13:5: 13:12 error: use of moved value: `*x` [E0382]
hello.rs:13     *x += 5;
                ^~~~~~~
hello.rs:8:19: 11:6 note: `x` moved into closure environment here because it has type `[closure(())]`, which is non-copyable
hello.rs:8     thread::spawn(move || {
hello.rs:9         let result = 5 + *x;
hello.rs:10         tx.send(result);
hello.rs:11     });
note: in expansion of closure expansion
hello.rs:8:19: 11:6 note: expansion site
hello.rs:8:19: 11:6 help: perhaps you meant to use `clone()`?
hello.rs:13:5: 13:12 error: cannot assign to immutable `Box` content `*x`
hello.rs:13     *x += 5;
                ^~~~~~~

Pattern Matching

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

Option andpattern matching

let msg = Some("howdy");

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

Closures

let nums = [1, 2, 3];
let square = |x| x * x;

let max: Vec<i32> = nums.iter().map(square).collect();

Generics

fn foo<A, B>(x: A, y: B) {
    // ...
}

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 Vec<T> {
    fn length(&self) -> u32 { 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

Introductions

  • The Rust Programming Language
  • Rust By Example

Discussion Fora

  • http://{users,internals}.rust-lang.org
  • /r/rust
  • #rust on irc.mozilla.org
  • This Week in Rust

Code

https://github.com/rust-lang/rust

Thank you! <3

@steveklabnik