Words are my own I do not speak for GoDaddy, Mozilla, or the Rust project.
Programming Language Rant
Systems Languages
C and pointers were a revolution - Finally a HIGH level language
C++ -- HIGH level in that you need to be HIGH to appreciate it
C# -- Oh clever another horizontal line -- and foreach
C++11 -- Oh yeah we can have foreach too, but we still call it for.
ObjectiveC -- All your user base are belong to iPhone.
Systems Languages
Every single C descendent puts memory safety on the user.
Enter Memory Safe Languages
Java*, Perl, PHP, Python, Ruby, node.js -- All do GC and take memory control away from programmer.
*java still has pointers but doesn't do arthmetic on them
GC languages can struggle with concurrency
Java VM pauses threads to GC objects.
Python, Ruby, etc. have Global Interpreter Lock when executing Python code
Shiny New Systems Languages
Go - Compiled duck-typed and syntax sugar for concurrency. Runs inside Go runtime with GC to avoid memory management.
Rust - Compiled, strong-typed with generics. Explicit scoped memory management and object lifetimes expressed in language.
Why not Go?
It's a great language, and easier to learn. But it only goes halfway into systems programming success, where Rust can give you as much control as C, and has the added bonus of Generics
Rust For your Brain
Explicit Mutability and borrow rules reduce need for unit tests
Strong typing also means not having to unit test as much.
Trait system gives some of the dynamic language flexibility back
use std::fmt;
struct Bus {
name: &'static str,
}
struct Train {
line: &'static str,
}
struct Plane {
callsign: &'static str,
}
impl fmt::Display for Bus {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} bus", self.name)
}
}
impl fmt::Display for Train {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} train", self.line)
}
}
impl fmt::Display for Plane {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} flight", self.callsign)
}
}
fn main() {
let b1 = Bus { name: "LAX Flyaway" };
let t1 = Train { line: "Pacific Coastliner"};
let p1 = Plane { callsign: "El Mariachi"};
println!("I took the {} to the {} and then hopped on the {}.", b1, t1, p1);
}
No easier in Python
class Bus(object):
def __init__(self, name):
self.name = name
def __str__(self):
return "%s bus" % (self.name,)
class Train(object):
def __init__(self, line):
self.line = line
def __str__(self):
return "%s train" % (self.line,)
class Plane(object):
def __init__(self, callsign):
self.callsign = callsign
def __str__(self):
return "%s plane" % (self.callsign,)
b1 = Bus("LAX Flyaway")
t1 = Train("Pacific Coastliner")
p1 = Plane("El Mariachi")
print("I took the {} to the {} and then hopped on the {}.".format(b1, t1, p1))
"Fearless Concurrency" -- Go ahead and make a thread, we dare you
Explicit mutability makes it easy to find global mutation
Built in Send/Sync traits for objects allow compile time identification of thread safe objects
Deadlock detection is still NP-complete. -- Hooray we get to keep our jobs
You can opt out of these safeguards when you need to.
use std::cell::RefCell;
use std::thread;
let result = thread::spawn(move || {
let c = RefCell::new(5);
let m = c.borrow_mut();
let b = c.borrow(); // this causes a panic
}).join();
assert!(result.is_err());
Opt-in to garbage collection when you need flexible data ownership.
use std::rc::Rc;
struct Owner {
name: String,
// ...other fields
}
struct Gadget {
id: i32,
owner: Rc,
// ...other fields
}
fn main() {
// Create a reference-counted `Owner`.
let gadget_owner: Rc = Rc::new(
Owner {
name: "Gadget Man".to_string(),
}
);
// Create `Gadget`s belonging to `gadget_owner`. Cloning the `Rc`
// value gives us a new pointer to the same `Owner` value, incrementing
// the reference count in the process.
let gadget1 = Gadget {
id: 1,
owner: Rc::clone(&gadget_owner),
};
let gadget2 = Gadget {
id: 2,
owner: Rc::clone(&gadget_owner),
};
// Dispose of our local variable `gadget_owner`.
drop(gadget_owner);
// Despite dropping `gadget_owner`, we're still able to print out the name
// of the `Owner` of the `Gadget`s. This is because we've only dropped a
// single `Rc`, not the `Owner` it points to. As long as there are
// other `Rc` values pointing at the same `Owner`, it will remain
// allocated. The field projection `gadget1.owner.name` works because
// `Rc` automatically dereferences to `Owner`.
println!("Gadget {} owned by {}", gadget1.id, gadget1.owner.name);
println!("Gadget {} owned by {}", gadget2.id, gadget2.owner.name);
// At the end of the function, `gadget1` and `gadget2` are destroyed, and
// with them the last counted references to our `Owner`. Gadget Man now
// gets destroyed as well.
}
Rust For Your Team
For your dev team...
Programming languages aren't just for computers.
Having explicit mutability and reference lifetimes helps be clear to humans too.
important = dict() # Will this change? When? What goes in it?
use std::collections::HashMap;
let mut important: HashMap = HashMap::new();
English/Chinese/Spanish/Hindi/etc. are all terrible at representing abstract concepts succinctly and clearly. Say it with code!
For your ops team...
Finding bugs at compile time means throwing better stuff over the wall to ops*.
Compiling borrowing v0.1.0 (file:///Users/cbyrum/src/SpamapS/presentation/borrowing)
error[E0505]: cannot move out of `pyth` because it is borrowed
--> src/main.rs:20:30
|
20 | users.insert(&pyth.name, pyth);
| --------- ^^^^ move out of `pyth` occurs here
| |
| borrow of `pyth.name` occurs here
error[E0505]: cannot move out of `kant` because it is borrowed
--> src/main.rs:21:30
|
21 | users.insert(&kant.name, kant);
| --------- ^^^^ move out of `kant` occurs here
| |
| borrow of `kant.name` occurs here
error: aborting due to 2 previous errors
error: Could not compile `borrowing`.
To learn more, run the command again with --verbose.
For your Dev & Ops...
How things get built and deploy matters. Ruby/Perl/Python packaging can be a nightmare.
C/C++ have layers on layers of dependency hell even after existing for 30 years.
New langs, better package/build/deploy stories.
Go has nice tie-ins with git and builds static binaries
Rust's "Cargo" tool is extremely well thought out and well integrated with crates.io for easy code re-use.
Nodepool? Call nodepool team. Zuul? Call zuul team. Wait.. JAVA?! ALWAYS JAVA
For your Dev & Ops....
Runtimes matter
Rust For JusticeFirefox is aimed at freedom and privacy, and its authors, Mozilla.org, invented Rust.
This Is Unix Rust, I KNOW THIS
HTML Rendering engine rewritten in Rust -- "Servo"
CSS Rendering engine rewritten in Rust to be parallelized
Released in November -- super legit
Why would they do that?
Firefox's original C++-bound memory model is basically why Google Chrome/Chromium exists.
Rust authors experimented with the idea that less garbage collection and memory tied more concretely to scope would beat the Process memory model in the long run
THANK YOU
Clint Byrum -- @SpamapS on Freenode IRC and Twitter. http://fewbar.com/