Skip to content

Latest commit

 

History

History
439 lines (407 loc) · 9.71 KB

why-rust.org

File metadata and controls

439 lines (407 loc) · 9.71 KB

Why Rust?

Credit

What is Rust

A system programming C’s like: speed + control Python’s like: safety + expressive power

System

  • Minimal Runtime (no G/C)
  • Low level control over H/W
  • Suitable for writing O/S and web browsers:

An operating system for learning

Redox is a Unix-like Operating System written in Rust, aiming to bring the innovations of Rust to a modern microkernel and full set of applications

Servo is a modern, high-performance browser engine designed for both application and embedded use.

Rust is

Fast + Safe + Concurrent

Fast

  • Zero const abstractions* (@ compile time)
  • Static dispatching
  • Stack allocation
  • Get us to a C/C++ speed
  • No garbage collection

fibonacci.py

#!/usr/bin/env python3.4
def fib(n: int) -> int:
    if n < 3:
        return 1
    else:
        return fib(n-1) + fib(n-2)

if __name__ == '__main__':
    print("%s" % fib(38))

fibonacci.rs

fn fib(n: u64) -> u64 {
    if n < 3 {
        1
    } else {
        fib(n-1) + fib(n-2)
    }
}

fn main() {
    println!("{}", fib(38));
}

Benchmark

time ./fib_py.py
39088169
./fib_py.py  12.02s user  0.01s system  98% cpu  12.229 total

➜ time ./fib_rs
39088169
./fib_rs      0.35s user  0.00s system  99% cpu   0.355 total

Real Example

Fixing Python Performance with Rust / Armin Ronacher

Sentry processes over a billion errors every month. We’ve been able to scale most of our systems, but in the last few months, one component has stood out as a computational chokepoint: Python’s source map processing.

As of yesterday, we have dramatically cut down that processing time (and CPU utilization on our machines) by replacing our source map handling with a Rust module that we interface with from Python.

Safe

Automatic memory management

  • but no G/C

Formally defied

  • lifetime
  • ownership,
  • mutability,

No data races

Automatic

{
  let v = vec![1, 2, 3];
} // lifetime ends

Ownership

let v = vec![1, 2, 3];  // v owns the Vec<i32>
let u = v;              // ownership *moved* to u
let t = v;              // ERROR: used moved value: `v`

Borrowing

let v = vec![1, 2, 3];  // v owns the Vec<i32>
let w = &v;             // w borrow from v
let t = &v;             // OK

Ownership (again)

fn print(v: Vec<i32>) {
  println!("{:?}", v);
}

fn main() {
  let v = vec![1, 2, 3];
  print(v);
  print(v);      // ERROR: used moved value: `v`
}

Borrowing (again)

fn print(v: &Vec<i32>) {
  println!("{:?}", v);
}

fn main() {
  let v = vec![1, 2, 3];
  print(&v);
  print(&v);      // OK
}

Copy

#[derive(Copy, Clone)]
struct Rectangle {
  height: f64,
  width: f64,
}

fn main() {
  let r1 = Rectangle {
     height: 42.0,
     width: 3.14,
  };
  let r2 = r1; // Copy
}

Immutability

let v = vec![1, 2, 3];
v.push(4); // ERROR

mut

let mut v = vec![1, 2, 3];
v.push(4); // OK

Immutability (again)

fn mutate(v: &Vec<i32>) {
    v.push(4); // ERROR: cannot borrow immutable borrowed content `v` as mutable
}

fn main() {
    let v = vec![1, 2, 3];
    mutate(&v);
}

Mutation must be explicit

fn mutate(v: &mut Vec<i32>) {
    v.push(4);
}

fn main() {
    let mut v = vec![1, 2, 3];
    mutate(&mut v);
}

Shared Immutable State is Evil

let mut v = vec![1, 2 ,3];
let u = &v;
let t = &v;
let mut s = &v;  // ERROR: cannot borrow `v` as mutable because it is also borrowed as immutable

Borrowing + lifetime

fn main() {
    let mut u: &Vec<i32>;
    {
        let mut v = vec![1, 2, 3];
        u = &v; // ERROR: `v` does not live long enough
    }
}

Expressive

exercism.io/python/pangram

import string

def is_pangram(text):
    alphabet = set(iter(string.lowercase))
    return alphabet.issubset(set(c.lower() for c in text))

exercism.io/rust/pangram

use std::collections::HashSet;

pub fn is_pangram(sentence: &str) -> bool {
    let alphabet = "abcdefghijklmnopqrstuvwxyz".chars().collect::<HashSet<_>>();
    alphabet.is_subset(&sentence.to_lowercase().chars().collect::<HashSet<_>>())
}

pangram.py

import string

def is_pangram(text):
    alphabet = set(string.lowercase)
    return alphabet.issubset(set(text.lower()))

pangram.rs

use std::collections::HashSet;

pub fn is_pangram(sentence: &str) -> bool {
    let alphabet = "abcdefghijklmnopqrstuvwxyz".chars().collect::<HashSet<_>>();
    alphabet.is_subset(&sentence.to_lowercase().chars().collect::<HashSet<_>>())
}

More

  • The type system: struct + enum
  • Pattern matching: match
  • Static duck typing: traits + Generics
  • Concurrency: std::sync, Rayon, Tokio, …
  • Tooling: cargo, rustdoc, rustup, …
  • Ecosystem: Community + https://craits.io
  • Rust progress: 1.0 2015/05→ 1.14 2016/12
  • Rust ❤ Python: FFI, rust-cpython

Did not make the cut

Content left out of the presentation:

Hello, world!

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

Hello, Cargo!

➜ rust cargo new –bin hello Created binary (application) `hello` project ➜ rust cd hello

What we get

➜ hello git:(master) ✗ tree . ├── Cargo.toml └── src └── main.rs

1 directory, 2 files

TOML?

➜ hello git:(master) ✗ cat Cargo.toml

[package]
name = "hello"
version = "0.1.0"
authors = ["Chen Rotem Levy <[email protected]>"]

[dependencies]

Hello, world!

➜ hello git:(master) ✗ cat src/main.rs

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

cargo run

➜ hello git:(master) ✗ cargo run Compiling hello v0.1.0 (file:///home/chen/src/rust/hello) Finished debug [unoptimized + debuginfo] target(s) in 2.76 secs Running `target/debug/hello` Hello, world!

more Ownership and Borrowing

Ownership

#[derive(Debug)]
struct X;

fn main() {
    let x = X;
    let y = x;
    let z = x; // error[E0382]: use of moved value: `x`
}

Error messages in rust:

error[E0382]: use of moved value: `x`
 --> main.rs:7:9
  |
6 |     let y = x;
  |         - value moved here
7 |     let z = x;
  |         ^ value used here after move
  |
  = note: move occurs because `x` has type `X`,
          which does not implement the `Copy` trait
$ rustc --explain E0382 | wc
     61     287    1695

zv* So

fn print_x(x: X) -> X {
    println!("x: is {:?}", X);
    x
}
fn main() {
    let x = X;
    x = print_x(x);
    let y = x;
}

Borrowing

fn print_x(x: &X) {
    println!("x: {:?}", x);
}
fn main() {
    let x = X;
    foo(x);
    let y = x;
}

Concurrent

  • Well defined sharing semantics
  • Future library

The type system

Simple types

  • bool
  • char
  • i8/i16/i32/i64/isize
  • u8/u16/u32/u64/usize
  • f32/f64

More complex types

  • Tuples: (A, B, C, …)
  • Arrays: [T; usize]
  • Slice: &[T]
  • String slice: &str
  • Function: fn(A, B, …) -> X

struct

struct Person {
  String: name,
}

impl Person {
   fn greet(&self) {
      println!("Hello, {}", self.name);
   }
}

`

enum

enum Option {
  Some(i32),
  None,
}

fn check_option(op: &Option) {
   match(*op) {
     Some(n) => println!("We got a value {}", n),
     None => println!("Sorry, no value here"),
   }
}

The Traits system

struct Rectangle {
  widnth: f64;
  length: f64;
}

impl Rectangle {
  fn new(w: f64, l: f64) -> Rectangle {
    Rectangle { widnth: w, length: l }
  }
  fn area(&self) -> f64 {
    self.length * self.height
  }
}

Built in Traits

use std::fmt::{Display, Formatter, Result}

impl Display for Rectangle {
  fn fmt(&self, f: &mut Formatter) -> Result {
    write!(f, "{} x {}", self.length, self.height)
  }
}

Rust + Python

Difference

PythonRust
dynamic typedstatic typed
dynamic dispatchstatic dispatch
big runtimesmall runtime

Similarities

PythonRust
pip/setup-toolscargo
pypicrates.io

Bits of Python in rust

  • self
  • string formatting
  • Unicode strings
  • 1_000_000