Matt Gathu
https://slides.com/mattgathu/rusty
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
Mozilla starts sponsoring Rust in 2009.
Mozilla still the main sponsor.
Rust knows when the variable gets out of scope or its lifetime ends at compile time. (RAII)
Rust also allows some kind of garbage collection e.g. Reference Counting
C++ implementations obey the zero-overhead principle: What you don’t use, you don’t pay for [Stroustrup, 1994]. And further: What you do use, you couldn’t hand code any better.
– Stroustrup
None of Rust’s abstractions impose a global performance penalty
let a = [1, 2, 3];
let sum = a.iter().fold(0, |acc, &x| acc + x);
array = [1, 2, 3]
sum = array.inject(0){|sum,x| sum + x }
RUST
RUBY
Again, no garbage collector.
Can compile without stdlib
Monomorphisation specializes each use of a generic function with specific instance, based on the parameter types of calls to that function. (similar to C++)
Results in fast code that is specialized for every call-site and statically dispatched.
Rust means never having to close a socket
~ Yehuda Katz
Memory is managed through a set of rules that the compiler checks at compile time. No run-time costs are incurred for any of the ownership features.
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 reference cannot outlive its referent.
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 reference cannot be aliased.
A mutable reference is aliased if there exists another live reference to one of its ancestors or descendants.
Rust supports 1:1 threading model (OS threads).
It has NO green threading model.
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();
}
Threads or actors communicate by sending each other messages containing data.
Do not communicate by sharing memory; instead, share memory by communicating.
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);
}
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());
}
Much of Rust's concurrency is implemented in the standard library, not the language itself.
This allows for extensibility.
The Send and Sync traits are used for concurrency.
The Send marker trait indicates that ownership of that type may be transferred between threads. Almost every Rust type is Send.
The Sync marker trait indicates that a type is safe to have references to a value from multiple threads. (thread safe)
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::new();
vec.push(elem);
println!("{:?}", vec);
}
TYPE INFERENCE
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
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
$ 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!