Matt Gathu
https://slides.com/mattgathu/pyrusty
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.
fn main() {
for count in 0..3 {
println!("{}. Welcome to PyconKE!", count);
}
}
def main():
for count in range(3):
print("{}. Welcome to PyconKE!".format(count))
Rust uses the Resource Acquisition Is Initialization (RAII) technique.
// 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
Again, no garbage collector.
Can compile without stdlib
Results in fast code that is specialized for every call-site and statically dispatched.
Memory is managed through a set of rules that the compiler checks at compile time.
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.
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()
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()
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.
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
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!