Starting Rust From A Scripting Background

Follow Along: http://rust-from-a-scripting-background.readthedocs.org/en/latest/

Welcome!

You:

Today

What you can't get from the book:

Note

Rust is an extremely feature-rich language and introductions are usually taught in 1-2 full days of workshops. The best we can do in 1 hour is build your interest and motivation, and make sure you know what questions to ask as you get involved.

Systems Components and Programming

_images/mobo.png

Note

Let's make sure we're all on the same page about some stuff you might never have needed to think about before.

tl;dr, computers are dumb but compilers are smart.

https://people.cs.clemson.edu/~mark/uprog.html is a neat overview of very low-level stuff.

Memory

_images/stack-and-heap.png

RAM is quick to access but impermanent

Disk is slower to access but more permanent

Stack & Heap are abstractions for how a program manages its own memory

(https://en.wikipedia.org/wiki/Data_segment#/media/File:Typical_computer_data_memory_arrangement.png)

CPU

Assembly Language

To write smaller and faster programs, you have to think harder about exactly what the CPU is doing.

Compiled vs Interpreted Languages

Compiled:

Interpreted:

Note

Choose a compiled language when:

  • Speed/performance is essential
  • Can't afford runtime crashes
  • Targeting an embedded platform with ~0 storage/memory

Choose an interpreted lanaguage when:

  • You're more fluent in it and need the code done fast
  • Code performance isn't essential
  • Some cases of targeting multiple platforms

Systems vs Application Programming

Systems programming: (assembly, C, C++, Rust)

Applications programming: (Python, Ruby, Java)

Note

Systems programming prioritizes speed and performance, and traditionally has expected programmers to memorize all the rules for how not to make mistakes.

Systems vs Application Code

_images/lampstack.png

(https://en.wikipedia.org/wiki/LAMP_%28software_bundle%29#/media/File:LAMP_software_bundle.svg)

Note

Systems code (ie kernel, drivers, etc) is pretty much all C today.

Rust vs Other Systems Languages

Other languages

Safe Rust:

Note

If you're just getting started and targeting a normal platform (or want to add support for your obscure favorite), Rust is like an automated mentor

If you're contributing to an existing code base in another language or hunting a job at a C++-only shop, the things you learn from Rust will improve your code, but it might not be your best choice

Note

http://graydon2.dreamwidth.org/218040.html is a list of common systems programming "footguns" absent from Rust

Debugging Rust vs Others

Applications programming languages

Other systems languages:

Safe Rust:

Safe vs Unsafe Rust

_images/nested-boxes.png

Note

Imagine that it's possible to enumerate every valid program (valid = free from memory mismanagement bugs, use-after-free errors, array out of bounds, etc.). The set of programs which the Rust borrow checker accepts is slightly smaller, but guaranteed to be contained within, the set of all valid programs.

What happens when you want to write code that you can prove is valid, but the borrow checker won't accept? Use the unsafe keyword to take down the metaphorical guard rails for a small section of code.

When you're starting out, try to write only safe Rust. In cases where you must use unsafe, be sure to understand why.

The Rust Ecosystem

_images/ecosystem.png

Note

Now we're on the same page about the basic concepts of systems programming, let's take a high-level look at some things you'll need to know about Rust to start using it

Channels

"The stable release channel will provide pain-free upgrades, and the nightly channel will give early adopters access to unfinished features as we work on them."

Libraries

_images/crates-logo.png

Rustaceans

Installation Options

Just want to try it out?

Need one version, with Cargo?

Need several versions?

Your First Rust Project

$ cargo new myproject

OR

$ multirust run stable cargo new myproject

THEN

$ vim myproject/src/lib.rs

Let's Write Rust!

http://rustbyexample.com/

http://doc.rust-lang.org/stable/book/

https://github.com/carols10cents/rustlings

https://github.com/ctjhoa/rust-learning

Note

This part is basically section 4 of The Book (http://doc.rust-lang.org/stable/book/syntax-and-semantics.html) but skipping as much as possible.

Basic Syntax

// Main takes no arguments and returns nothing
fn main(){
    // The function body is the *scope* inside these curly braces
    // Create a variable. It owns a string.
    let what_to_say = "Hello World";
    // Meet print syntax
    println!("This program says {}", what_to_say);
}

http://rustbyexample.com/primitives/literals.html

Note

basic_syntax.rs http://rustbyexample.com/primitives/literals.html

4.1. Variable Bindings 4.2. Functions 4.3. Primitive Types 4.4. Comments 4.32. Operators

Scope Errors!

fn not_main(){
    let what_to_say = "Hello World";
}
fn main(){
    println!("This program says {}", what_to_say);
}
<anon>:5:42: 5:53 error: unresolved name `what_to_say` [E0425]
<anon>:5         println!("This program says {}", what_to_say);
                                                  ^~~~~~~~~~~
<std macros>:2:25: 2:56 note: in this expansion of format_args!
<std macros>:3:1: 3:54 note: in this expansion of print! (defined in <std
macros>)
<anon>:5:9: 5:55 note: in this expansion of println! (defined in <std macros>)
<anon>:5:42: 5:53 help: see the detailed explanation for E0425
error: aborting due to previous error

Punctuation Errors!

fn main(){
    let what_to_say = "Hello World"
    println!("This program says {}", what_to_say);
}
<anon>:6:9: 6:16 error: expected one of `.`, `;`, or an operator, found `println`
<anon>:6         println!("This program says {}", what_to_say);
                 ^~~~~~~

The compiler catches mistakes...

fn main(){
    let what_to_say = "Hello World"
    println!("Hello");
}
<anon>:4:13: 4:24 warning: unused variable: `what_to_say`,
#[warn(unused_variables)] on by default
<anon>:4         let what_to_say = "Hello World";
                     ^~~~~~~~~~~

Hey, Pythonistas!

fn main(){let what_to_say="Hello World";println!
("This program says {}",what_to_say);}
fn
main
(
    )
{
let what_to_say
    =
"Hello World"
;
println
!  (
"This program says {}"
    , what_to_say
) ;           }

Note

The only whitespace which matters is that which separates tokens. fnmain is different from fn main. Other than that, the compiler doesn't enforce any rules, though you can use https://github.com/manishearth/rust-clippy and https://github.com/rust-lang-nursery/rustfmt for formatting and style guidance

Primitive Types

Note

Have you ever been using a language without a strong type system, and returned a string from a function where you were expecting to get an int out? Rust forbids those bugs.

http://rustbyexample.com/primitives.html

Things each type can do are in standard library docs, like http://doc.rust-lang.org/stable/std/primitive.bool.html

Note

Here we're skipping book sections...

  • 4.11. Structs
  • 4.12. Enums
  • 4.16. Vectors
  • 4.17. Strings

Functions

http://doc.rust-lang.org/stable/book/functions.html

Functions have type signatures

_images/madlibs.png

Functions example

fn and(x: bool,  y: bool) -> bool{
    x && y
}
fn another_and(x: bool,  y: bool) -> bool{
    return x && y;
}
fn main() {
    println!("{}", and(true, false));
    println!("{}", another_and(true, false));
}

Note

function_and_operator.rs

4.15. Method Syntax 4.24. Universal Function Call Syntax

Errors returning values!

fn and(x: bool,  y: bool) -> bool{
    x && y;
}
...
<anon>:1:5: 3:6 error: not all control paths return a value [E0269]
<anon>:1     fn and(x: bool,  y: bool) -> bool{
<anon>:2         x && y;
<anon>:3     }
<anon>:1:5: 3:6 help: see the detailed explanation for E0269
<anon>:2:15: 2:16 help: consider removing this semicolon:
<anon>:2         x && y;
                       ^
error: aborting due to previous error

Errors if you get the types wrong!

fn and(x: bool,  y: bool) -> bool{
    return  3;
}
...
<anon>:2:15: 2:16 error: mismatched types:
 expected `bool`,
    found `_`
(expected bool,
    found integral variable) [E0308]
<anon>:2        return 3;
                       ^
<anon>:2:15: 2:16 help: see the detailed explanation for E0308

Conditionals

fn and(x: bool,  y: bool) -> i32{
    if x && y {
        return 3;
    }
    return 0;
}

Error: You've got to return what you said you would

fn and(x: bool,  y: bool) -> i32{
    if x && y {
        return 3;
    }
    // what if we don't do anything here?
}
<anon>:2:9: 4:10 error: mismatched types:
 expected `i32`,
    found `()`
(expected i32,
    found ()) [E0308]
<anon>:2         if x && y {
<anon>:3             return 3;
<anon>:4         }
...

Matching

fn main() {
    let number = 13;
    // TODO ^ Try different values for `number`

    println!("Tell me about {}", number);
    match number {
        // Match a single value
        1 => println!("One!"),
        // Match several values
        2 | 3 | 5 | 7 | 11 => println!("This is a prime"),
        // Match an inclusive range
        13...19 => println!("A teen"),
        // Handle the rest of cases
        _ => println!("Ain't special"),
    }
}

http://rustbyexample.com/flow_control/match.html

You can do things with match results

fn main() {
    let boolean = true;
    // Match is an expression too
    let binary = match boolean {
        // The arms of a match must cover all the possible values
        false => 0,
        true => 1,
        // TODO ^ Try commenting out one of these arms
    };

    println!("{} -> {}", boolean, binary);
}

http://rustbyexample.com/flow_control/match.html

Looping

fn main() {
    // `n` will take the values: 1, 2, ..., 100 in each iteration
    for n in 1..101 {
        if n % 15 == 0 {
            println!("fizzbuzz");
        } else if n % 3 == 0 {
            println!("fizz");
        } else if n % 5 == 0 {
            println!("buzz");
        } else {
            println!("{}", n);
        }
    }
}

http://rustbyexample.com/flow_control/for.html

Note

4.5. if 4.6. Loops 4.13. Match 4.14. Patterns 4.21. if let

Errors with loops: Scope still matters

fn main() {
    // `n` will take the values: 1, 2, ..., 100 in each iteration
    for n in 1..101 {
        ...
    }
    println!{"{}", n}
}
<anon>:14:24: 14:25 error: unresolved name `n` [E0425]
<anon>:14         println!{"{}", n}
                                 ^
<std macros>:2:25: 2:56 note: in this expansion of format_args!
<std macros>:3:1: 3:54 note: in this expansion of print! (defined in <std
macros>)
<anon>:14:9: 14:26 note: in this expansion of println! (defined in <std
macros>)
<anon>:14:24: 14:25 help: see the detailed explanation for E0425

Ownership & Borrowing

http://doc.rust-lang.org/stable/book/ownership.html

http://doc.rust-lang.org/stable/book/references-and-borrowing.html

The Rules

First, any borrow must last for a scope no greater than that of the owner.

Second, you may have one or the other of these two kinds of borrows, but not both at the same time:

  • one or more references (&T) to a resource,
  • exactly one mutable reference (&mut T).

(http://doc.rust-lang.org/stable/book/references-and-borrowing.html)

The Obligatory Book Metaphor

What if we broke those rules?

Borrowing Example

fn borrow_int(borrowed_int: &i32) {
    println!("I borrowed the int {}", borrowed_int);
}

fn main() {
    let my_int : i32 = 42;
    borrow_int(&my_int);
    println!("I still have my int. it's {}.", my_int)
}

http://rustbyexample.com/scope/borrow.html

Note

(~10mins)

4.7. Ownership 4.8. References and Borrowing 4.9. Lifetimes 4.26. const and static 4.10. Mutability

Borrowing: Simple types are copy.

fn main() {
    let immutable_int = 42;
    println!("immutable_int contains {}", immutable_int);
    let mut mutable_int = immutable_int; // this makes a copy
    println!("mutable_int contains {}", mutable_int);
    println!("immutable_int contains {}", immutable_int);
    mutable_int = 5;
    println!("mutable_int now contains {}", mutable_int);
}
immutable_int contains 42
mutable_int contains 42
immutable_int contains 42
mutable_int now contains 5

Borrowing: Non-Copy types

metadata.

fn main() {
    let immutable = "I'm immutable!".to_string();
    println!("immutable contains {}", immutable);
    let mut mutable = immutable; //move the value, not copy
    println!("mutable contains {}", mutable);
    mutable = "I have been mutated".to_string();
    println!("mutable now contains {}", mutable);
}
immutable_string contains I'm immutable!
mutable_string contains I'm immutable!
mutable_string now contains I have been mutated

Borrowing Errors: Can't use after move

fn main() {
    let immutable = "I'm immutable!".to_string();
    let mut mutable = immutable; //move the value, not copy
    println!("immutable contains {}", immutable);
}
<anon>:5:43: 5:52 error: use of moved value: `immutable` [E0382]
<anon>:5         println!("immutable contains {}", immutable);
                                                   ^~~~~~~~~
...
<anon>:5:43: 5:52 help: see the detailed explanation for E0382
<anon>:4:13: 4:24 note: `immutable` moved here because it has type
`collections::string::String`, which is moved by default
<anon>:4         let mut mutable = immutable; //move the value, not copy
                     ^~~~~~~~~~~

What we skipped

Note

4.18. Generics
4.19. Traits 4.22. Trait Objects 4.23. Closures 4.27. Attributes 4.28. type aliases 4.29. Casting between types 4.30. Associated Types 4.31. Unsized Types 4.33. Deref coercions 4.34. Macros 4.35. Raw Pointers

What next?

http://rust-from-a-scripting-background.readthedocs.org/en/latest/