Rust

(for JS developers?)

Links

http://www.rust-lang.org/

Also pointers to guides, docs, etc

 

http://discuss.rust-lang.org/

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

If you want to know whats going on

RFCs

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

Invasive language changes need to go through the RFC process. Some are *really* well written and you can learn a lot about API design and programming in general by reading some.

My rust story

  • Some time ago at ViennaJS:
  • How learning Haskell changed my view on ES6 and got me into Spidermonkey Development (https://slides.com/swatinem/haskell-es6)
     
  • I was thinking about learning about Rust for a long time

And then this happened:

Need a use-case

Get to the point already!

Rust is…

  • an efficient, low level, systems programming language
  • developed by Mozilla
  • focused on memory safety with a key focus on ownership and borrowing
  • but also focused on developer productivity and ease of use, with zero cost abstractions
  • still a bit in flux, with some fine tuning still happening before it reaches 1.0

Ownership and Borrowing

  • One variable / structure has the ownership of a value;
    when it goes out of scope, it is freed
  • Can have multiple read-only references (borrows)
  • Can have a single mutable borrow
  • Those things are enforced on compile time
     
  • But it has support for custom smart pointers, reference counting and multiple mutable references with locking at runtime

OOP?

  • Kind of
  • Structs/Tuples/Enums for data encapsulation
  • Impls/Traits for functionality
     
  • Extremely flexible and nice to work with (IMO)
     
  • No Exceptions! \o/
  • Rather uses Rust enums for recoverable Errors:
  • Result<T, Err> or Option<T>
     
  • Macros!

For JS developers?

  • Rust uses LLVM, there have been experiments using it with emscripten
    … but those haven’t lead to anything so far :-(
     
  • Mozilla is using Rust to develop Servo
  • Servo is the next generation rendering engine, focused on performance, stability, parallelization and embedding
  • *loooooong* term goal is to replace Gecko with Servo
struct Size {
  rows: u32,
  cols: u32
}

enum Step {
  N, E, S, W
}

impl Step {
  fn apply(&self, Size{rows, cols}: Size, index: u32) -> Option<u32> {
    match *self {
      N if index >= cols => Some(index - cols),
      E if (index + 1) % cols > 0 => Some(index + 1),
      S if index + cols < rows * cols => Some(index + cols),
      W if index % cols > 0 => Some(index - 1),
      _ => None
    }
  }
}

cont.

// simplified!
fn apply_path(size: Size, steps: &Vec<Step>) -> Result<u32, u32> {
  let mut index = start;
  for (i, step) in steps.iter().enumerate() {
    match step.apply(size, index) {
      // valid move, to new index i
      Some(newindex) => {
        index = newindex;
      },
      // invalid move
      None => {
        return Err(i + 1)
      }
    }
  }
  Ok(steps.len())
}

Conclusion?

  • Rust is fun!
  • Structs/Enums + Traits is just sooooo much better than single Inheritance OOP + Interfaces
  • Same goes for Result/Option vs. Expections
  • It’s really refreshing to work low level and close to the metal. But its so convenient too!
  • Don’t have to care about async! Everything is blocking!
    If I want to do things in parallel, I can spawn threads or use channels + select!()
     
  • I would love to use it more often / in production

BUT!

  • Still some backwards incompat changes before 1.0
    (its currently at alpha, the final scheduled for march)
  • Some Compile Errors around borrowing, lifetimes and traits are just confusing
  • And sometimes the compiler is just stupid / too restrictive

Example

// fails:
			let input = file.read_to_string().unwrap().as_slice().words();

../boilerplate.rs:57:16: 57:46 error: borrowed value does not live long enough
../boilerplate.rs:57 			let input = file.read_to_string().unwrap().as_slice().words();
                     			            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../boilerplate.rs:52:35: 59:4 note: reference must be valid for the block at 52:34...
                     ...
../boilerplate.rs:57:4: 57:65 note: ...but borrowed value is only valid for the statement at 57:3;
consider using a `let` binding to increase its lifetime
../boilerplate.rs:57 			let input = file.read_to_string().unwrap().as_slice().words();
                     			^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to previous error

// works:
			let slice = file.read_to_string().unwrap();
			let input = slice.as_slice().words();

Problem is this:

`.words()` takes a reference (pointer to a string buffer) and returns
an Iterator of references into that buffer (pointers)

But the buffer (read_to_string()) does not live long enough,
because it is not bound to a variable.

A variable binding (and its lexical scope) would define its lifetime,
that’s what the compiler says.
But (1) you have to understand what the compiler is actually telling you
and (2) you still don’t get it why the compiler can’t just *do the right thing*

The End!

try it yourself!

Rust

By Arpad Borsos

Rust

  • 1,837