Why Try Rust?

Warning: Language nerd presenting

Rust is a systems programming language that runs blazingly fast, prevents segfaults, and guarantees thread safety.

What am I selling?


fn main() {
    println!("Hello World!");
}

Hello World

struct Person {
    name: String
}

impl Person {
    fn greet(&self) {
        println!("Hello {}", self.name)
    }
}

fn main() {
    let dylan = Person { name: String::from("Dylan") };
    dylan.greet();
}

fn main() {
    let mut number = 0;
    number += 1;
}

Best Parts

  • Error handling
  • Ownership
  • Traits
  • Macros
  • Crates Ecosystem
  • Tooling

Disclaimer: This is according to me

The Borrow Checker!

  • Lifetimes + References
  • Ownership rules
fn string_length(input: &String) -> usize {
    input.len()
}

References

fn shout(input: &mut String) {
    input.push_str("!");
}
fn string_length(input: &String) -> usize {
    input.len()
}

fn shout(input: &mut String) {
    input.push_str("!");
}

fn main() {
    let name = String::from("Dylan");
    let length = string_length(&name);
    println!("{}", length);
    shout(&mut name); // Compilation error
    println!("{}", name);
}

References

error[E0596]: cannot borrow immutable local variable `name` as mutable
  --> src/main.rs:84:16
   |
80 |     let name = String::from("Dylan");
   |         ---- consider changing this to `mut name`
...
84 |     shout(&mut name);
   |                ^^^^ cannot borrow mutably
fn string_length(input: &String) -> usize {
    input.len()
}

fn shout(input: &mut String) {
    input.push_str("!");
}

fn main() {
    let name = String::from("Dylan");
    let length = string_length(&name);
    println!("{}", length); // 5
    let mut name = name;
    shout(&mut name);
    println!("{}", name); // Dylan!
}

References

fn string_length(input: &String) -> usize {
    input.len()
}

fn shout(input: &mut String) {
    input.push_str("!");
}

fn consume(input: String) {
    println!("Nom nom nom {}", input);
}

fn main() {
    let name = String::from("Dylan");
    consume(name);
    let length = string_length(&name); // Compilation error
    println!("{}", length);
}

Ownership rules

Error Handling

  • No exceptions
  • Result<T, E>
  • Option<T>
fn might_fail() -> Result<u8, String> {
    // ...
}


enum Result<T, E> {
    Ok(T),
    Err(E),
}

Error Handling

#[derive(Debug)]
enum MathError {
    DivisionByZero,
    NonPositiveLogarithm,
    NegativeSquareRoot,
}

type MathResult = Result<f64, MathError>;

fn div(x: f64, y: f64) -> MathResult {
    if y == 0.0 {
        Err(MathError::DivisionByZero)
    } else {
        Ok(x / y)
    }
}

fn speed(dist: f64, time: f64) -> MathResult {
    let result = div(dist, time)?;
    Ok(result)
}

fn main() {
    println!("Speed: {}", speed(10.0, 4.0).unwrap());
}

Error Handling - Error Type

#[derive(Debug)]
enum MathError {
    DivisionByZero,
    NonPositiveLogarithm,
    NegativeSquareRoot,
}

type MathResult = Result<f64, MathError>;

Error Handling - Returning

#[derive(Debug)]
enum MathError {
    DivisionByZero,
    NonPositiveLogarithm,
    NegativeSquareRoot,
}

type MathResult = Result<f64, MathError>;

fn div(x: f64, y: f64) -> MathResult {
    if y == 0.0 {
        Err(MathError::DivisionByZero)
    } else {
        Ok(x / y)
    }
}

Error Handling - Calling

type MathResult = Result<f64, MathError>;

fn div(x: f64, y: f64) -> MathResult {
    // ...
}

fn speed(dist: f64, time: f64) -> MathResult {
    let result: f64 = div(dist, time)?;
    Ok(result)
}

Error Handling - unwrap

type MathResult = Result<f64, MathError>;

fn speed(dist: f64, time: f64) -> MathResult {
    // ...
}

fn main() {
    println!("Speed: {}", speed(10.0, 4.0).unwrap());
}

Type System

  • Powerful type system
  • Union enums
struct Person {
    first_name: String,
    second_name: String,
    address: Address,
}

Learn by doing...

struct Person {
    first_name: String,
    second_name: String,
    address: Address,
}

struct Address {
    number: StreetNumber,
    street: String,
    city: String,
}
struct Person {
    first_name: String,
    second_name: String,
    address: Address,
}

struct Address {
    number: StreetNumber,
    street: String,
    city: String,
}

enum StreetNumber {
    House(u32),
    Unit{unit: u32, street: u32}
}

Multi-Paradigm

  • Separates structure from behaviour with traits
  • Has similar feel of OO, dot notation, etc.
  • Pattern matching
struct Person {
    first_name: String,
    second_name: String,
    address: Address,
}

impl Person {
    fn new(first_name: String, second_name: String, address: Address) -> Person {
        Person {
            first_name,
            second_name,
            address
        }
    }
    
    fn full_name(&self) -> String {
        format!("{} {}", self.first_name, self.second_name)
    }       

}
trait Greet {
    fn greet(&self);
}

struct Person {
    first_name: String,
    second_name: String,
    address: Address,
}

impl Person {
    fn full_name(&self) -> String {
        format!("{} {}", self.first_name, self.second_name)
    }    

}

impl Greet for Person {
    fn greet(&self) {
        println!("Hello {}", self.full_name());
    }
}

enum StreetNumber {
    House(u32),
    Unit{unit: u32, street: u32}
}

impl ToString for StreetNumber {
    fn to_string(&self) -> String {
        match self {
            StreetNumber::House(num) => format!("{}", num),
            StreetNumber::Unit{unit, street} => format!("{}/{}", unit, street)
        }
    }
}

Macros

  • Not as scary, crazy as C macros
  • Has typing in the macro system
  • Great opportunity for removal of boiler plate
  • Two types: declarative and procedural
impl Person {
    fn full_name(&self) -> String {
        format!("{} {}", self.first_name, self.second_name)
    }    

}

Declarative

Procedural

#[derive(Debug)]
struct Person {
    first_name: String,
    second_name: String,
    address: Address,
}

#[derive(Debug)]
struct Address {
    number: StreetNumber,
    street: String,
    city: String,
}

#[derive(Debug)]
enum StreetNumber {
    House(u32),
    Unit{unit: u32, street: u32}
}

WASM

  • Web Assembly
  • Write compiled languages for browser

Tooling

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

Cargo

Only ONE tool!

[package]
name = "bk-releases"
version = "0.1.0"
authors = ["Dylan Maccora <maccora17@gmail.com>"]

[dependencies]
reqwest = "0.8.*"
serde = "1"
serde_derive = "1"
serde_json = "1"
failure = "0.1"
url = "1.7"
clap = "2.32"
chrono = "0.4"
Compiling playground v0.0.1 (file:///playground)
error[E0532]: expected tuple struct/variant, found struct variant `StreetNumber::Unit`
  --> src/main.rs:58:13
   |
58 |             StreetNumber::Unit(unit, street) => format!("{}/{}", unit, street)
   |             ^^^^^^^^^^^^^^^^^^ did you mean `StreetNumber::Unit { /* fields */ }`?

error: aborting due to previous error

For more information about this error, try `rustc --explain E0532`.
Cargo.toml

Other Tooling

  • Active support (rust-lang-nursery)
    • rustfmt
    • RLS
    • clippy
    • crates.io
  • No dedicated IDE yet but improving

Check it out!

  • Rust Playground
    https://play.rust-lang.org/
  • Rust Book
    https://doc.rust-lang.org/book/second-edition
  • Rust by Example
    https://rustbyexample.com/

Or talk to me!

Made with Slides.com