Introducing Rust

Matt Gathu

@swissgathu

https://slides.com/mattgathu/rustintro

Rust is a systems  language that pursues the trifecta of:

  • speed

  • safety

  • concurrency

A Brief History

The Graydon Years (2006-2010)

Graydon Hoare's side project.

 

I have been writing a compiled, concurrent, safe, systems programming language for the past four and a half years.

~ July 2010

The Mozilla Years (2009-2015)

Mozilla starts sponsoring Rust in 2009.

 

Post 1.0.0 (2015-)

Mozilla still the main sponsor.

 

Community contribution:

Syntax

fn main() {
    for count in 0..3 {
        println!("{}.Welcome to Rust Meetup!",count);
    }
}

Speed

No Garbage Collection

Rust uses the Resource Acquisition Is Initialization (RAII) technique.

 

LLVM

Zero Cost Abstractions

// use inbuilt sort
let mut array = [1, 2, 3];
array.sort();

// use a comparator function
let mut array = [1, 2, 3];
array.sort_by(|a, b| a.cmp(b));
# use inbuilt sort
lst = [2, 1, 3]
lst.sort()

# use a comparator function
lst = [2, 1, 3]
lst.sort(cmp=lambda a, b: cmp(a,b))

RUST

PYTHON

Minimal Runtime

  • Again, no garbage collector.

  • Can compile without stdlib

Generics monomorphization

Results in fast code that is specialized for every call-site and statically dispatched.

Safety

Ownership

 

Memory is managed through a set of rules that the compiler checks at compile time.

 

Rules of Ownership

 
  • Each value has its owner.
  • There can only be one owner at a time.
  • When the owner goes out of scope, the value will be dropped.

 

fn as_str(data: &u32) -> &str {
    // compute the string
    let s = format!("{}", data);

    // (this does not compile in Rust)
    &s
}
// s goes out of scope and is freed here

A value cannot outlive its owner.

let mut data = vec![1, 2, 3];
// get an internal reference
let x = &data[0];

// (this does not compile in Rust)
data.push(4);

println!("{}", x);

A mutable value cannot be shared/aliased.

A mutable reference is aliased if there exists another live reference to one of its ancestors or descendants.

Concurrency

Threads

Rust supports 1:1 threading model (OS threads).

use std::thread;

fn main() {
    let handle = thread::spawn(|| {
        for i in 1..10 {
            println!("hi number {} from the spawned thread!", i);
        }
    });

    for i in 1..5 {
        println!("hi number {} from the main thread!", i);
    }

    let _ = handle.join();
}
from threading import Thread


def main():

    def target():
        for i in range(10):
            print("hi number {} from the spawned thread!".format(i))

    thread = Thread(target=target)
    thread.start()

    for i in range(5):
        print("hi number {} from the main thread!".format(i))

    thread.join()

Message Passing

Threads or actors communicate by sending each other messages containing data.

 

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

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

    thread::spawn(move || {
        let val = String::from("hi");
        tx.send(val).unwrap();
    });

    let received = rx.recv().unwrap();
    println!("Got: {}", received);
}
from queue import Queue
from threading import Thread

# A thread that produces data
def producer(queue):
    # Produce some data
    queue.put("hi")

# A thread that consumes data
def consumer(queue):
    # Get some data
    data = queue.get()
    print("Received: {}".format(data))
       
# Create the shared queue and launch both threads
q = Queue()
t1 = Thread(target=consumer, args=(q,))
t2 = Thread(target=producer, args=(q,))
t1.start()
t2.start()

Shared State

Mutexes

use std::sync::{Mutex, Arc};
use std::thread;

fn main() {
    let counter = Arc::new(Mutex::new(0));
    let mut handles = vec![];

    for _ in 0..10 {
        let counter = counter.clone();
        let handle = thread::spawn(move || {
            let mut num = counter.lock().unwrap();

            *num += 1;
        });
        handles.push(handle);
    }

    for handle in handles {
        handle.join().unwrap();
    }

    println!("Result: {}", *counter.lock().unwrap());
}

Extensible Concurrency

Much of Rust's concurrency is implemented in the standard library, not the language itself.

 

This allows for extensibility.

Send & Sync

The Send and Sync traits are used for concurrency.

Why Rust

  • high level abstractions
  • type inference
  • functional style support
  • rust once, run everywhere
  • rustfmt
void RemoveSpaces(char* source)
{
  char* i = source;
  char* j = source;
  while(*j != 0)
  {
    *i = *j++;
    if(*i != ' ')
      i++;
  }
  *i = 0;
}
fn remove_spaces(s: &str) -> String {
    s.replace(" ", "")
}

HIGH LEVEL ABSTRACTION

fn main() {
    
    let elem = 5u8;

    // let mut vec: Vec<u8> = Vec::new();
    let mut vec = Vec::new();

    vec.push(elem);

    println!("{:?}", vec);
}

TYPE INFERENCE

Functional Support

  • Closures
  • Iterators
  • Traits
fn main() {
let mut v = [5, 4, 1, 3, 2];

v.sort_by(|a, b| a.cmp(b));

assert!(v == [1, 2, 3, 4, 5]);

// reverse sorting
v.sort_by(|a, b| b.cmp(a));

assert!(v == [5, 4, 3, 2, 1]);

}

CLOSURES

#![feature(inclusive_range_syntax)]

for i in (0...10).rev().filter(|x| (x % 2 == 0)) {
  print!("{} ", i);
}
// output: 10 8 6 4 2 0
let cities = ["Nairobi", "Mombasa", "Kisumu"];
let populations = [2_750_547, 799_668, ‎216_479];

let matrix = cities.iter().zip(populations.iter());

for (c, p) in matrix {
  println!("{:10}: population = {}", c, p);
}
// output:
// Nairobi   : population = 2750547
// Mombasa   : population = 799668
// Kisumu    : population = 216479

ITERATORS

pub trait Summarizable {
    fn summary(&self) -> String;
}
pub struct Tweet {
    pub username: String,
    pub content: String,
    pub reply: bool,
    pub retweet: bool,
}

impl Summarizable for Tweet {
    fn summary(&self) -> String {
        format!("{}: {}", self.username, self.content)
    }
}

TRAITS

Rust Once, Run Everywhere

Interoperability with other languages using a Foreign Function Interface (FFI)

from ctypes import cdll

lib = cdll.LoadLibrary('target/debug/libdouble_input.dylib')
double_input = lib.double_input

input = 4
output = double_input(input)
print('{} * 2 = {}'.format(input, output))
#[no_mangle]
pub extern fn double_input(input: i32) -> i32 {
    input * 2
}

RUST

PYTHON

Ecosystem

$ cargo new hello_world --bin

cargo new

$ cd hello_world
$ tree .
.
├── Cargo.toml
└── src
    └── main.rs

1 directory, 2 files

Cargo.toml

[package]
name = "hello_world"
version = "0.1.0"
authors = ["Matt Gathu <mattgathu@gmail.com>"]

src/main.rs

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

cargo build

$ cargo build
   Compiling hello_world v0.1.0 (file:../hello_world)
$ cargo run
     Fresh hello_world v0.1.0 (file:../hello_world)
   Running `target/hello_world`
Hello, world!

Getting Started

curl https://sh.rustup.rs -sSf | sh

Stay Oxidized!

Made with Slides.com