Tree @master (Download .tar.gz)
rust.md @master — view markup · raw · history · blame
% The Rust Programming Language % G.D. Ritter % June 2015
The Rust Programming Language
A new systems programming language being developed by Mozilla Research, with an emphasis on correctness while still allowing for very low-level programing by emphasizing zero-cost abstractions.
Low-Level Programming
Low-Level Programming
\begin{center} \includegraphics[width=.9\textwidth]{imgs/kanye-water-bottle-01.png} \end{center}
Low-Level Programming
\begin{center} \includegraphics[width=.9\textwidth]{imgs/kanye-water-bottle-02.png} \end{center}
Systems Programming Languages
System software is computer software designed to operate and control the computer hardware and to provide a platform for running application software, and includes such things as operating systems, utility software, device drivers, compilers, and linkers.
—Wikipedia
"Systems programs" means "programs where the constant factors are important".
—Comment by
neelk
on Lambda the Ultimate
Systems Programming Languages
Example Program
A program that:
- Defines a
point
struct. - Gives that
point
struct two machine integers as fields. - Defines an
add
function that takes and returns twopoint
s by value. - Has a
main
function that:- Creates a
point
on the stack - Creates a
point
on the heap - Adds the two (after dereferencing the second)
- Prints the result
- Frees the second point
- Creates a
Systems Programming Languages
C
typedef struct { int x, y; } point;
point add(point a, point b) {
point result = { a.x + b.x, a.y + b.y };
return result;
}
void main(int argc, char* argv[]) {
point a = { 1, 2 };
point* b = malloc(sizeof(point));
b->x = 4; b->y = 3;
point c = add(a, *b);
printf("{.x = %d, .y = %d}\n", c.x, c.y);
free(b);
}
Systems Programming Languages
C++
struct point {
int x, y;
point(int _x, int _y) { x = _x; y = _y; }
point add(point other) {
return point(x + other.x, y + other.y);
}
};
int main(int argc, char* argv[]) {
point a(1, 2);
point* b = new point(4, 3);
point c = a.add(*b);
cout << "{ .x = " << c.x;
cout << ", .y = " << c.y << " }" << endl;
delete b;
}
Systems Programming Languages
Go
type Point struct { X, Y int }
func (a Point) add(b Point) Point {
return Point{ a.X + b.X, a.Y + b.Y }
}
func main() {
a := Point{1, 2}
b := new(Point)
b.X, b.Y = 4, 3
fmt.Println(a.add(*b))
// No free, because Go is garbage-collected
}
Systems Programming Languages
D
struct Point {
int x, y;
Point add(Point other) {
return Point(this.x + other.x, this.y + other.y);
}
}
void main() {
Point a = Point(1, 2);
Point* b = cast(Point*)GC.malloc(Point.sizeof);
b.x = 4; b.y = 3;
writeln(a.add(*b));
GC.free(b);
}
Systems Programming Languages
Nim
type Point = tuple[x: int, y: int]
proc add(a: Point, b: Point): Point =
(x: a.x + b.x, y: a.y + b.y)
var a : Point
var b : ptr Point
a = (x: 1, y: 2)
b = cast[ptr Point](alloc(sizeof(Point)))
b.x = 4
b.y = 3
echo(add(a, b[]))
dealloc(b)
Systems Programming Languages
Rust
#[derive(Debug,Clone,Copy)]
struct Point { x: isize, y: isize }
fn add(l: Point, r: Point) -> Point {
Point { x: l.x + r.x, y: l.y + r.y }
}
fn main() {
let a = Point { x: 1, y: 2 };
let b = Box::new(Point { x: 4, y: 3 });
println!("{:?}", add(a, *b));
}
What Makes Rust Interesting
Ownership
\begin{center} \includegraphics[width=.9\textwidth]{imgs/dawkins-owned.png} \end{center}
Preliminary Zero
Mutability
fn factorial(n: usize) -> usize {
let result = 1;
while n > 0 {
result *= n;
n -= 1;
}
result
}
Preliminary Zero
Mutability is NOT THE DEFAULT
fn factorial(n: usize) -> usize {
let result = 1;
while n > 0 {
result *= n; /* ERROR */
n -= 1; /* ERROR */
}
result
}
Preliminary Zero
Mutability is Opt-In
fn factorial(mut n: usize) -> usize {
let mut result = 1;
while n > 0 {
result *= n;
n -= 1;
}
result
}
Preliminary One
Polymorphism (although not on this slide)
fn i32_id(a: i32) -> i32 {
a
}
fn make_i32_pair(left: i32, right: i32) -> (i32, i32) {
(left, right)
}
Preliminary One
Polymorphism (this slide is, like, totally polymorphic)
fn id<T>(a: T) -> T {
a
}
fn make_pair<A, B>(left: A, right: B) -> (A, B) {
(left, right)
}
Preliminary Two
Traits
struct MyNum { num: i32 }
trait Sayable {
fn say(&self);
}
impl Sayable for MyNum {
fn say(&self) {
println!(".oO( MyNum {{ num: {:?} }} )", self.num);
}
}
Preliminary Two
Traits
fn main() {
(MyNum { num: 3 }).say();
}
Output
.oO( MyNum { num: 3 } )
Preliminary Three
Traits and Polymorphism
fn say_twice<T: Sayable>(t: T) {
t.say(); t.say();
}
fn main() {
say_twice(MyNum { num: 7 });
}
Output
.oO( NyNum { num: 7 } )
.oO( NyNum { num: 7 } )
Preliminary Three
Traits and Polymorphism
fn print_eq<A: Eq + Sayable>(left: A, right: A) {
if left == right {
println!("these are equal:");
left.say();
right.say();
} else {
println!("these are not equal:");
left.say();
right.say();
}
}
Preliminary Four
Built-In Traits
/* slightly simplified from the real definition */
trait PartialEq {
fn eq(&self, other: &Self) -> bool;
fn ne(&self, other: &Self) -> bool;
}
/* no more methods, but more laws */
trait Eq: PartialEq { }
Preliminary Four
Implementing Built-In Traits
struct MyNum { num: i32 }
impl PartialEq for MyNum {
fn eq(&self, other: &MyNum) -> bool {
self.num == other.num
}
}
impl Eq for MyNum { }
Preliminary Four
Implementing Built-In Traits Automatically
/* or just this */
#[derive(PartialEq,Eq)]
struct MyNum { num: i32 }
Preliminary Four
Format-String-Related Traits
/* in the stdlib: */
trait Debug {
fn fmt(&self, &mut Formatter) -> Result;
}
/* so, on on our type: */
#[derive(Debug)]
struct MyNum { num: i32 }
What Makes Rust Interesting
Ownership
#[derive(Debug)]
struct MyNum { num: i32 }
fn main() {
let x = MyNum { num: 2 };
println!("x = {:?}", x);
/* prints "x = MyNum { num: 2 }" */
}
What Makes Rust Interesting
Ownership
#[derive(Debug)]
struct MyNum { num: i32 }
fn main() {
let x = MyNum { num: 2 };
let y = x;
println!("x = {:?}", x);
/* doesn't compile */
}
What Makes Rust Interesting
Ownership
#[derive(Debug)]
struct MyNum { num: i32 }
fn main() {
let x = MyNum { num: 2 };
let y = x; /* <- value moves here */
println!("x = {:?}", x);
}
What Makes Rust Interesting
Ownership
#[derive(Debug)]
struct MyNum { num: i32 }
fn main() {
let x = MyNum { num: 2 };
let y = x;
println!("x = {:?}", x);
/* so it does not live until the print */
}
What Makes Rust Interesting
Ownership --- Explicit Cloning
#[derive(Debug, Clone)]
struct MyNum { num: i32 }
fn main() {
let x = MyNum { num: 2 };
let y = x.clone(); /* explicit clone */
println!("x = {:?}", x);
/* but this works! */
}
What Makes Rust Interesting
Ownership --- Implicit Copying
#[derive(Debug, Clone, Copy)]
struct MyNum { num: i32 }
fn main() {
let x = MyNum { num: 2 };
let y = x; /* implicit copy */
println!("x = {:?}", x);
/* as does this! */
}
What Makes Rust Interesting
Ownership --- Destructors
#[derive(Debug)]
struct MyNum { num: i32 }
impl Drop for MyNum {
fn drop(&mut self) {
println!("dropping: {:?}", self)
}
}
fn main() {
let x = MyNum { num: 2 };
println!("x = {:?}", x);
}
What Makes Rust Interesting
Ownership --- Destructors
fn main() {
let x = MyNum { num: 2 };
println!("x = {:?}", x);
}
Output
x = MyNum { num: 2 }
dropping: MyNum { num: 2 }
What Makes Rust Interesting
Ownership --- Special Clones
#[derive(Debug)]
struct MyNum { num: i32 }
impl Clone for MyNum {
fn clone(&self) -> Self {
println!("Cloning a MyNum...");
MyNum { num: self.num }
}
}
fn main() {
let x = MyNum { num: 2 };
let y = x.clone();
println!("x = {:?}", x);
}
Ownership --- Special Clones
fn main() {
let x = MyNum { num: 2 };
let y = x.clone()
println!("x = {:?}", x);
}
Output
Cloning a MyNum...
x = MyNum { num: 2 }
What Makes Rust Interesting
Owned Pointers --- "Boxes"
fn main() {
let x = Box::new(5);
println!("x + 1 = {:?}", *x + 1);
}
What Makes Rust Interesting
Owned Pointers --- "Boxes"
fn main() {
/* this acts like a `malloc` */
let x = Box::new(5);
/* this dereferences the pointer */
println!("x + 1 = {:?}", *x + 1);
/* as soon as ownership passes out
* of scope, the box is freed */
}
What Makes Rust Interesting
References
\begin{center} \includegraphics[width=.9\textwidth]{imgs/dril-owned.png} \end{center}
What Makes Rust Interesting
References
#[derive(Debug)]
struct MyNum { num: i32 }
fn some_func(_: MyNum) {
println!("yeah, whatevs");
}
fn main() {
let x = MyNum { num: 2 };
some_func(x);
println("{:?}", x);
}
What Makes Rust Interesting
References
#[derive(Debug)]
struct MyNum { num: i32 }
fn some_func(_: MyNum) {
println!("yeah, whatevs");
}
fn main() {
let x = MyNum { num: 2 };
some_func(x);
println("{:?}", x);
/* ERROR: use of moved value */
}
What Makes Rust Interesting
References
#[derive(Debug)]
struct MyNum { num: i32 }
fn some_func(_: MyNum) -> MyNum {
println!("yeah, whatevs");
}
fn main() {
let x = MyNum { num: 2 };
let y = some_func(x.clone());
println("{:?}", y);
/* works---but so tedious! */
}
What Makes Rust Interesting
References
#[derive(Debug,Clone)]
struct MyNum { num: i32 }
fn some_func(_: MyNum) {
println!("yeah, whatevs");
}
fn main() {
let x = MyNum { num: 2 };
some_func(x.clone());
println("{:?}", x);
/* works---but not what we want */
}
What Makes Rust Interesting
References
#[derive(Debug)]
struct MyNum { num: i32 }
fn some_func(_: &MyNum) {
println!("yeah, whatevs");
}
fn main() {
let x = MyNum { num: 2 };
some_func(&x);
println("{:?}", x);
/* works! */
}
What Makes Rust Interesting
Dangling References...?
fn main() {
let mut my_ref: &i32 = &5;
{
let x = 7;
my_ref = &x;
}
println!("{:?}", my_ref);
}
What Makes Rust Interesting
Dangling References... are statically prevented
fn main() {
let mut my_ref: &i32 = &5;
{
let x = 7;
my_ref = &x; /* ERROR: does not live long enough */
}
println!("{:?}", my_ref);
}
What Makes Rust Interesting
"The Borrow Checker"
fn main() {
let mut my_vec = vec![];
{
let x = 7;
my_vec.push(&x); /* also a problem */
}
println!("{:?}", my_vec);
}
What Makes Rust Interesting
Lifetime Quandary
fn keep_left<T>(left: &T, right: &T) -> &T {
left
}
What Makes Rust Interesting
Lifetime Quandary
fn keep_left<'l, 'r, T>(left: &l T,
right: &r T) -> &l T {
left
}
A Slightly Longer Example
A Linked List
#[derive(Debug)]
enum List<T> {
Cons(T, Box<List<T>>),
Nil,
}
fn cons<T>(car: T, cdr: List<T>) -> List<T> {
List::Cons(car, Box::new(cdr))
}
fn nil<T>() -> List<T> {
List::Nil
}
A Slightly Longer Example
A Linked List
fn head<T>(list: &List<T>) -> Option<&T> {
match *list {
Nil => None,
Cons(ref x, _) => Some(&x),
}
}
A Slightly Longer Example
A Linked List Lifetime
fn main() {
let mut h = None;
{
let lst = cons("this",
cons("that",
cons("the other",
nil())));
h = head(lst);
}
println!("{:?}", h);
}
A Slightly Longer Example
Linked List: A Lifetime Original Picture
fn head<'a, T>(list: &'a List<T>) -> Option<&'a T> {
match *list {
Nil => None,
Cons(ref x, _) => Some(&x),
}
}
A Slightly Longer Example
Linked List: A Lifetime Original Picture
fn polycephaly<T>(left: &List<T>, right: &List<T>)
-> Option<(&T, &T)> {
match (*left, *right) {
(List::Nil, List::Nil) => None,
(List::Cons(ref x, _),
List::Cons(ref y, _)) => Some(y, x)
}
}
A Slightly Longer Example
You May Find Yourself Living in a Shotgun Shack
fn polycephaly<'l, 'r, T>(left: &'l List<T>,
right: &'r List<T>)
-> Option<(&'r T, &'l T)> {
match *left {
List::Cons(ref x, _) => match *right {
List::Cons(ref y, _) => Some((y, x)),
_ => None,
},
_ => None,
}
}