Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Rust Me, I'm a Developer!

Rust Me, I'm a Developer!

A brief overview of Rust. Currently for Rust v0.10

Greg Malcolm

April 04, 2014
Tweet

More Decks by Greg Malcolm

Other Decks in Programming

Transcript

  1. UST ME,
    I’m a developer!
    gregmalcolm
    speakerdeck: gregmalcolm/rust-me-im-a-developer
    “Rust me, I’m a developer”. A beginners overview of Rust.

    View full-size slide

  2. True Facts !
    About Me
    gregmalcolm
    speakerdeck: gregmalcolm/rust-me-im-a-developer
    Blah blah blah, my name is Greg Malcolm. Currently I’m working with Ruby on Rails and Javascript. The job before that I worked with embedded C++.
    The job before that I worked with .NET and Java. And so on. See the pattern? I enjoy trying out new languages. And my quest for the new and shiny has
    lead me to…

    View full-size slide

  3. True Facts !
    About Me
    Not from Wisconsin…
    gregmalcolm
    speakerdeck: gregmalcolm/rust-me-im-a-developer
    Do they drink tea in Peru?
    Nah, Australian right?
    Blah blah blah, my name is Greg Malcolm. Currently I’m working with Ruby on Rails and Javascript. The job before that I worked with embedded C++.
    The job before that I worked with .NET and Java. And so on. See the pattern? I enjoy trying out new languages. And my quest for the new and shiny has
    lead me to…

    View full-size slide

  4. Rust is currently on version 0.10. Until we get to version 1.0 the code is subject to radical change. That said things are starting to calm down a lot, and
    version 1.0 should be coming out in the next year.

    View full-size slide

  5. An alternative to C and C++
    RUST is a “Systems Programming Language”. It’s for writing software that serves the platform rather than the application layer; So it’s competing with the
    likes of C and C++.
    !
    Let’s talk about C and C++ for a moment. The upside of working with C and C++ is it’s really fast and efficient and really takes you close to the metal. It
    allows you to address the computers memory systems directly and will compile natively on any operating system. It’s as good as it gets without resorting
    to assembly language programming which can be difficult to maintain. It also stays clear of using garbage collection, which drains resources and causes
    periodic slowdowns. However, there are downsides, one of those being that it’s really easy to accidentally introduce bugs that blow up intermittently and
    when you least expect it. Tracking down these problems can be very tricky. More on that in a bit.

    View full-size slide

  6. use std::io::timer::sleep;
    !
    // Rust 0.10
    fn main() {
    let actions = [("Captain America", "bashes", 20),
    ("Black Widow", "slashes", 25),
    ("Ironman", "throws cash at", 0),
    ("Hulk", "SMASHES", 200)];
    !
    let mut outcomes =
    actions.iter()
    .map(|&action| {
    let (hero, attack, damage) = action;
    format!("{:s} {:s} Red Skull for {:d} damage",
    hero, attack, damage)
    });
    !
    for outcome in outcomes {
    spawn(proc() {
    sleep(500);
    println!(“{:s}”, outcome);
    });
    }
    }
    Rust sample
    Lets take a look at a little sample as a taster…
    !
    In this scenario the Avengers have just rolled for initiative in a battle against Red Skull we want to show the results.
    !
    The actions are declared in the form of a vector of tuples. Rust calls arrays “vectors”, much like C++. Each tuple is made up of a hero string, an attack
    string and an integer value giving damage.
    !
    Next we need to figure out the outcome of each action to output. We iterate though each action tuple transforming the tuple into a string using the map()
    method. Ruby developers will notice the inside of map() looks similar to a Ruby block. This is called a closure in Rust. Inside the closure we’ll decode the
    tuple contents to hero, attack and damage variables. format!() will create a sanitized string output replacing the {:s}, {:s} and {:d} with hero, attack and
    damage.
    !
    Finally in the for loop at the end we’ll iterate through each outcome string and display it. We’re wrapping the println!() statement in a spawn() block to
    make each output happen asynchronously in it’s own lightweight thread. Rust is really good at concurrency and multithreading, we’ll talk about that later.
    The sleep() statement helps induce the 4 outcomes to display in random order.

    View full-size slide

  7. Rust sample
    $ rustc intro.rs !
    $ ./intro !
    Captain America bashes Red Skull for 20 damage!
    Ironman throws cash at Red Skull for 0 damage!
    Black Widow slashes Red Skull for 25 damage!
    Hulk SMASHES Red Skull for 200 damage!
    $ ./intro!
    Black Widow slashes Red Skull for 25 damage!
    Captain America bashes Red Skull for 20 damage!
    Ironman throws cash at Red Skull for 0 damage!
    Hulk SMASHES Red Skull for 200 damage!
    $
    I compile the sample using the compiler, rustc. This will give me a native binary that I can execute.

    View full-size slide

  8. Consider browsers…
    Let’s talk about browsers. Browsers need to be extremely fast. Therefore all the major browsers make use of a lot of C/C++ code. For example I think read
    somewhere that Mozilla uses something like 7 million lines of C and C++. When you’ve got that much C++ code safety is a problem. So much so that
    Mozilla have started funding Rust as a full time research project as an alternative language providing speed, efficiency AND safety. They are currently using
    it to build a new experimental browser, called…

    View full-size slide

  9. … Servo. Named after Tom Servo, one of the robots in MST3K.

    View full-size slide

  10. int main() {
    char *str = "BOOM";
    str[0] = 'Z';
    !
    return 0;
    }
    C
    Boom!
    Let’s take a look at life in C. Anyone guess what this code does? Well, it look’s like it’s trying to change the word BOOM into ZOOM. Only problem is that
    we’ve initialized it to the string “ZOOM” which actually makes it a constant. Does the compiler tell you? No.

    View full-size slide

  11. int main() {
    char *str = "BOOM";
    str[0] = 'Z';
    !
    return 0;
    }
    C
    $ clang boom.c -o boom
    $
    Boom!
    Let’s take a look at life in C. Anyone guess what this code does? Well, it look’s like it’s trying to change the word BOOM into ZOOM. Only problem is that
    we’ve initialized it to the string “ZOOM” which actually makes it a constant. Does the compiler tell you? No.

    View full-size slide

  12. int main() {
    char *str = "BOOM";
    str[0] = 'Z';
    !
    return 0;
    }
    C
    $ clang boom.c -o boom !
    $ ./boom !
    [1] 38116 bus error ./boom!
    $
    Boom!
    However when we do see a problem at runtime. It turns out that when a string is defined this way, it’s actually a constant string. Therefore changing out
    the first character causes explosions.

    View full-size slide

  13. int main() {
    char *str = "BOOM";
    str[0] = 'Z';
    !
    return 0;
    }
    C
    $ clang boom.c -o boom !
    $ ./boom !
    [1] 38116 bus error ./boom!
    $
    Boom!
    However when we do see a problem at runtime. It turns out that when a string is defined this way, it’s actually a constant string. Therefore changing out
    the first character causes explosions.

    View full-size slide

  14. Boom!
    fn main() {
    let s = ~"BOOM";
    s.shift_char();
    s.unshift_char('Z');
    !
    println!("It go {:s}", s);
    }
    Rust
    Here is a similar version of the code written in Rust. Putting a “~” in front of the string makes it an “owned pointer” to a string on the heap which we need
    to do if we want a changeable string. Don’t worry about that too much for now. We use shift_char() to remove the ‘B’, and unshift_char() to prepend a ‘Z’
    in it’s place.
    !
    Rust warns you about problems at compile time rather than runtime. Compiling this program exposes a problem: “cannot borrow immutable local variable
    as mutable”. Turns out that Rust actually defines immutable constants by default. This is advantageous for optimization and concurrency concerns.

    View full-size slide

  15. Boom!
    fn main() {
    let s = ~"BOOM";
    s.shift_char();
    s.unshift_char('Z');
    !
    println!("It go {:s}", s);
    }
    $ rustc less_boom.rs
    less_boom.rs:3:5: 3:6 error: cannot borrow immutable local variable as mutable
    less_boom.rs:3 s.shift_char();
    ^
    less_boom.rs:4:5: 4:6 error: cannot borrow immutable local variable as mutable
    less_boom.rs:4 s.unshift_char('Z');
    ^
    Rust
    Here is a similar version of the code written in Rust. Putting a “~” in front of the string makes it an “owned pointer” to a string on the heap which we need
    to do if we want a changeable string. Don’t worry about that too much for now. We use shift_char() to remove the ‘B’, and unshift_char() to prepend a ‘Z’
    in it’s place.
    !
    Rust warns you about problems at compile time rather than runtime. Compiling this program exposes a problem: “cannot borrow immutable local variable
    as mutable”. Turns out that Rust actually defines immutable constants by default. This is advantageous for optimization and concurrency concerns.

    View full-size slide

  16. Boom!
    fn main() {
    let mut s = ~"BOOM";
    s.shift_char();
    s.unshift_char('Z');
    !
    println!("It go {:s}", s);
    }
    Rust
    We just need to add “mut” to the declaration to make the variable mutable. Fixed!

    View full-size slide

  17. Boom!
    fn main() {
    let mut s = ~"BOOM";
    s.shift_char();
    s.unshift_char('Z');
    !
    println!("It go {:s}", s);
    }
    $ rustc less_boom.rs
    $
    Rust
    We just need to add “mut” to the declaration to make the variable mutable. Fixed!

    View full-size slide

  18. Boom!
    fn main() {
    let mut s = ~"BOOM";
    s.shift_char();
    s.unshift_char('Z');
    !
    println!("It go {:s}", s);
    }
    $ rustc less_boom.rs!
    $ ./less_boom!
    It go ZOOM!
    $
    Rust
    And it executes too.

    View full-size slide

  19. #include
    #include
    int main() {
    int *dangler = NULL;
    if (true) {
    int temp=23;
    dangler = &temp;
    }
    printf("Dangler equals: %d \n", *dangler);
    !
    return 1;
    }
    Dangling Pointers
    C
    That last example was a little unfair. C++ would have handled it more gracefully. Dangling pointers however are a very serious issue in C and C++. Let’s
    take a look at how this sample works…

    View full-size slide

  20. #include
    #include
    int main() {
    int *dangler = NULL;
    if (true) {
    int temp=23;
    dangler = &temp;
    }
    printf("Dangler equals: %d \n", *dangler);
    !
    return 1;
    }
    Dangling Pointers
    C
    ‘dangler’ is defined as pointer to an integer. It is located at memory address 0x1E00.
    !
    Next ‘dangler’ is set to point to the variable ‘temp’ at memory location 0x1E01. If dereferenced it will return the value 23.
    !
    However, dangler is dereferenced on the printf statement after the temp variable goes out of scope. What will happen when we reach this line?

    View full-size slide

  21. #include
    #include
    int main() {
    int *dangler = NULL;
    if (true) {
    int temp=23;
    dangler = &temp;
    }
    printf("Dangler equals: %d \n", *dangler);
    !
    return 1;
    }
    Dangling Pointers
    C
    The Stack
    0x1E00 dangler
    !
    !
    =NULL
    ‘dangler’ is defined as pointer to an integer. It is located at memory address 0x1E00.
    !
    Next ‘dangler’ is set to point to the variable ‘temp’ at memory location 0x1E01. If dereferenced it will return the value 23.
    !
    However, dangler is dereferenced on the printf statement after the temp variable goes out of scope. What will happen when we reach this line?

    View full-size slide

  22. #include
    #include
    int main() {
    int *dangler = NULL;
    if (true) {
    int temp=23;
    dangler = &temp;
    }
    printf("Dangler equals: %d \n", *dangler);
    !
    return 1;
    }
    Dangling Pointers
    C
    The Stack
    0x1E00 dangler
    0x1E01 temp =23
    =&0x1E01 (23)
    ‘dangler’ is defined as pointer to an integer. It is located at memory address 0x1E00.
    !
    Next ‘dangler’ is set to point to the variable ‘temp’ at memory location 0x1E01. If dereferenced it will return the value 23.
    !
    However, dangler is dereferenced on the printf statement after the temp variable goes out of scope. What will happen when we reach this line?

    View full-size slide

  23. #include
    #include
    int main() {
    int *dangler = NULL;
    if (true) {
    int temp=23;
    dangler = &temp;
    }
    printf("Dangler equals: %d \n", *dangler);
    !
    return 1;
    }
    Dangling Pointers
    C
    The Stack
    0x1E00 dangler=&0x1E01 (?)
    !
    0x1E01 temp =23
    ‘dangler’ is defined as pointer to an integer. It is located at memory address 0x1E00.
    !
    Next ‘dangler’ is set to point to the variable ‘temp’ at memory location 0x1E01. If dereferenced it will return the value 23.
    !
    However, dangler is dereferenced on the printf statement after the temp variable goes out of scope. What will happen when we reach this line?

    View full-size slide

  24. #include
    #include
    int main() {
    int *dangler = NULL;
    if (true) {
    int temp=23;
    dangler = &temp;
    }
    printf("Dangler equals: %d \n", *dangler);
    !
    return 1;
    }
    $ clang dangle.c -o dangle
    $
    Dangling Pointers
    C
    ‘dangler’ is defined as pointer to an integer. It is located at memory address 0x1E00.
    !
    Next ‘dangler’ is set to point to the variable ‘temp’ at memory location 0x1E01. If dereferenced it will return the value 23.
    !
    However, dangler is dereferenced on the printf statement after the temp variable goes out of scope. What will happen when we reach this line?

    View full-size slide

  25. #include
    #include
    int main() {
    int *dangler = NULL;
    if (true) {
    int temp=23;
    dangler = &temp;
    }
    printf("Dangler equals: %d \n", *dangler);
    !
    return 1;
    }
    Dangling Pointers
    C
    The answer is “undetermined”. This time around we actually get back 23 because the memory hasn’t been reallocated yet. But what if the memory had
    been reallocated? Maybe 9 times out of 10 this line will return the expected result in production. And on the other occasion crash the program. What if
    you changed the value referenced at this location? You could be changing memory in some other part of the application. Could get crazy! These kinds of
    problems can spot during testing, let alone troubleshooting and fixing.

    View full-size slide

  26. #include
    #include
    int main() {
    int *dangler = NULL;
    if (true) {
    int temp=23;
    dangler = &temp;
    }
    printf("Dangler equals: %d \n", *dangler);
    !
    return 1;
    }
    $ clang dangle.c -o dangle!
    $ ./dangle !
    Dangler equals: 23 !
    $
    Dangling Pointers
    C
    The answer is “undetermined”. This time around we actually get back 23 because the memory hasn’t been reallocated yet. But what if the memory had
    been reallocated? Maybe 9 times out of 10 this line will return the expected result in production. And on the other occasion crash the program. What if
    you changed the value referenced at this location? You could be changing memory in some other part of the application. Could get crazy! These kinds of
    problems can spot during testing, let alone troubleshooting and fixing.

    View full-size slide

  27. fn main() {
    let dangler;
    if true {
    let temp = 23;
    dangler = &temp;
    }
    println!("Dangler equals: {:d}", *dangler);
    }
    Rust
    Dangling Pointers
    Not a problem in Rust. It’ll warn you at compile time that you’re doing something hazardous. Let’s try compiling this.

    View full-size slide

  28. fn main() {
    let dangler;
    if true {
    let temp = 23;
    dangler = &temp;
    }
    println!("Dangler equals: {:d}", *dangler);
    }
    $ rustc less_dangle.rs
    less_dangle.rs:5:19: 5:24 error: `temp` does not live long enough
    less_dangle.rs:5 dangler = &temp;
    ^~~~~
    less_dangle.rs:1:11: 8:2 note: reference must be valid for the block at 1:10...
    less_dangle.rs:1 fn main() {
    less_dangle.rs:2 let dangler;
    less_dangle.rs:3 if (true) {
    less_dangle.rs:4 let temp = 23;
    less_dangle.rs:5 dangler = &temp;
    less_dangle.rs:6 }
    ...
    less_dangle.rs:3:15: 6:6 note: ...but borrowed value is only valid for the block at
    less_dangle.rs:3 if (true) {
    Rust
    Dangling Pointers
    Not a problem in Rust. It’ll warn you at compile time that you’re doing something hazardous. Let’s try compiling this.

    View full-size slide

  29. fn main() {
    let dangler;
    if true {
    let temp = 23;
    dangler = &temp;
    }
    println!("Dangler equals: {:d}", *dangler);
    }
    less_dangle.rs:7:39: 7:46 error: use of possibly uninitialized variable: `dangler`!
    less_dangle.rs:7 println!("Dangler equals: {:d}", *dangler);!
    ^~~~~~~
    Rust
    Dangling Pointers
    First problem: it doesn’t like that we’re potentially initializing dangler in an inconsistent way.

    View full-size slide

  30. fn main() {
    let dangler;
    if true {
    let temp = 23;
    dangler = &temp;
    } else {
    // dangler isn’t defined for this case!
    }
    println!("Dangler equals: {:d}", *dangler);
    }
    Dangling Pointers
    Rust
    less_dangle.rs:7:39: 7:46 error: use of possibly uninitialized variable: `dangler`!
    less_dangle.rs:7 println!("Dangler equals: {:d}", *dangler);!
    ^~~~~~~
    Ok, this one is one me. By declaring dangler on the outside of the if statement and then defining it inside I’ve made the definition ambiguous. What if
    there was an else cause? It could be defined as something else entirely.

    View full-size slide

  31. fn main() {
    let dangler;
    {
    let temp = 23;
    dangler = &temp;
    }
    println!("Dangler equals: {:d}", *dangler);
    }
    less_dangle.rs:5:19: 5:24 error: `temp` does not live long enough!
    less_dangle.rs:5 dangler = &temp;!
    ^~~~~!
    less_dangle.rs:1:11: 8:2 note: reference must be valid for the block at 1:10!
    ...!
    less_dangle.rs:3:15: 6:6 note: ...but borrowed value is only valid for the block at 3:14!
    less_dangle.rs:3 if (true) {!
    less_dangle.rs:4 let temp = 23;!
    less_dangle.rs:5 dangler = &temp;!
    less_dangle.rs:6 }
    Dangling Pointers
    Rust
    No problem. We don’t really need an if statement, let’s just use empty braces instead.
    !
    Next up: “temp does not live long enough”. Yup! We used dangler after it “died”.
    !
    But what’s this? “Borrowed value does not live long enough”? What does that mean?

    View full-size slide

  32. fn main() {
    let dangler;
    {
    let temp = 23;
    dangler = &temp;
    }
    println!("Dangler equals: {:d}", *dangler);
    }
    less_dangle.rs:5:19: 5:24 error: `temp` does not live long enough!
    less_dangle.rs:5 dangler = &temp;!
    ^~~~~!
    less_dangle.rs:1:11: 8:2 note: reference must be valid for the block at 1:10!
    ...!
    less_dangle.rs:3:15: 6:6 note: ...but borrowed value is only valid for the block at 3:14!
    less_dangle.rs:3 if (true) {!
    less_dangle.rs:4 let temp = 23;!
    less_dangle.rs:5 dangler = &temp;!
    less_dangle.rs:6 }
    Dangling Pointers
    Rust
    No problem. We don’t really need an if statement, let’s just use empty braces instead.
    !
    Next up: “temp does not live long enough”. Yup! We used dangler after it “died”.
    !
    But what’s this? “Borrowed value does not live long enough”? What does that mean?

    View full-size slide

  33. Borrowing (&)
    let shield = Shield::new();
    1) For this scenario Captain America has created a shield so he can fight crime.
    2) But Stephen Colbert wants to fight crime too!
    3) Stephen Colbert borrows the shield by dereferencing the shield variable. Stephen now has the shield so Captain America can’t use it while he has it.
    4) But because this is called “borrowing”, Stephen eventually has to return the shield. Now Captain America can now go back to fighting crime,and
    Stephen Colbert can go back to feeling sad.

    View full-size slide

  34. Borrowing (&)
    let shield = Shield::new();
    1) For this scenario Captain America has created a shield so he can fight crime.
    2) But Stephen Colbert wants to fight crime too!
    3) Stephen Colbert borrows the shield by dereferencing the shield variable. Stephen now has the shield so Captain America can’t use it while he has it.
    4) But because this is called “borrowing”, Stephen eventually has to return the shield. Now Captain America can now go back to fighting crime,and
    Stephen Colbert can go back to feeling sad.

    View full-size slide

  35. Borrowing (&)
    let colbert = &shield;
    1) For this scenario Captain America has created a shield so he can fight crime.
    2) But Stephen Colbert wants to fight crime too!
    3) Stephen Colbert borrows the shield by dereferencing the shield variable. Stephen now has the shield so Captain America can’t use it while he has it.
    4) But because this is called “borrowing”, Stephen eventually has to return the shield. Now Captain America can now go back to fighting crime,and
    Stephen Colbert can go back to feeling sad.

    View full-size slide

  36. Borrowing (&)
    1) For this scenario Captain America has created a shield so he can fight crime.
    2) But Stephen Colbert wants to fight crime too!
    3) Stephen Colbert borrows the shield by dereferencing the shield variable. Stephen now has the shield so Captain America can’t use it while he has it.
    4) But because this is called “borrowing”, Stephen eventually has to return the shield. Now Captain America can now go back to fighting crime,and
    Stephen Colbert can go back to feeling sad.

    View full-size slide

  37. fn main() {
    let dangler;
    {
    let temp = 23;
    dangler = &temp;
    }
    println!("Dangler equals: {:d}", *dangler);
    }
    Rust
    Dangling Pointers
    less_dangle.rs:5:19: 5:24 error: `temp` does not live long enough!
    less_dangle.rs:5 dangler = &temp;!
    ^~~~~!
    less_dangle.rs:1:11: 8:2 note: reference must be valid for the block at 1:10!
    ...!
    less_dangle.rs:3:15: 6:6 note: ...but borrowed value is only valid for the block at 3:14!
    less_dangle.rs:3 if (true) {!
    less_dangle.rs:4 let temp = 23;!
    less_dangle.rs:5 dangler = &temp;!
    less_dangle.rs:6 }
    So dangler was borrowing the reference to temp and didn’t return it before temp expired. That’s not so much borrowing as stealing! And Rust will have no
    truck with that kind of behavior.
    This is one of the mechanisms Rust uses to keep track of all memory allocations and thus prevent Bad Things happening.

    View full-size slide

  38. So lets talk about pointers some more. Shared pointers!

    View full-size slide

  39. I’ll explain in the form of a code sample emulating a famous scene from the film Spartacus where Spartacus is trying to surrender to the romans, by
    declaring “I’m Spartacus”. One of his men then yells “No, I’m Spartacus”. And then they all start yelling it. It’s a fun thing to shout!

    View full-size slide

  40. I’ll explain in the form of a code sample emulating a famous scene from the film Spartacus where Spartacus is trying to surrender to the romans, by
    declaring “I’m Spartacus”. One of his men then yells “No, I’m Spartacus”. And then they all start yelling it. It’s a fun thing to shout!

    View full-size slide

  41. fn main() {
    let spartacus = ~"Spartacus";
    println!("I'm {:?}!", spartacus);
    }
    Owned Pointers (~)
    So, here’s that squiggle again. Ok, a tilde if you insist! Rather than declaring Spartacus as a stack variable I’d like to allocate it on the Heap instead. That
    way it’s not going to disappear just because it’s lost scope. Also if I’d created it statically, it would just get stored as a series of unchangeable byte
    characters.
    !
    On this occasion I’m formatting the output using the {:?} type. This displays the content as “debugger information” rather than casting it as something
    specific. It’s ugly and computationally expensive though, so no putting it in production code!

    View full-size slide

  42. fn main() {
    let spartacus = ~"Spartacus";
    println!("I'm {:?}!", spartacus);
    }
    Owned Pointers (~)
    So, here’s that squiggle again. Ok, a tilde if you insist! Rather than declaring Spartacus as a stack variable I’d like to allocate it on the Heap instead. That
    way it’s not going to disappear just because it’s lost scope. Also if I’d created it statically, it would just get stored as a series of unchangeable byte
    characters.
    !
    On this occasion I’m formatting the output using the {:?} type. This displays the content as “debugger information” rather than casting it as something
    specific. It’s ugly and computationally expensive though, so no putting it in production code!

    View full-size slide

  43. fn main() {
    let spartacus = ~"Spartacus";
    println!("I'm {:?}!", spartacus);
    }
    I'm ~"Spartacus"!
    Owned Pointers (~)
    So, here’s that squiggle again. Ok, a tilde if you insist! Rather than declaring Spartacus as a stack variable I’d like to allocate it on the Heap instead. That
    way it’s not going to disappear just because it’s lost scope. Also if I’d created it statically, it would just get stored as a series of unchangeable byte
    characters.
    !
    On this occasion I’m formatting the output using the {:?} type. This displays the content as “debugger information” rather than casting it as something
    specific. It’s ugly and computationally expensive though, so no putting it in production code!

    View full-size slide

  44. fn main() {
    let spartacus = ~"Spartacus";
    println!("I'm {:?}!", spartacus);
    !
    let wonder_woman = spartacus;
    println!("No, I'm {:?}!!", wonder_woman);
    }
    Owned Pointers (~)
    Next up Wonder Woman steps in to take the rap. She takes ownership of the owned pointer by assigning herself to the spartacus variable. Only one
    variable is actually allowed to own an owned pointer, so ownership Moves to Wonder Woman moving it away from Spartacus. So now Wonder Woman
    gets to be Spartacus!

    View full-size slide

  45. fn main() {
    let spartacus = ~"Spartacus";
    println!("I'm {:?}!", spartacus);
    !
    let wonder_woman = spartacus;
    println!("No, I'm {:?}!!", wonder_woman);
    }
    Owned Pointers (~)
    Next up Wonder Woman steps in to take the rap. She takes ownership of the owned pointer by assigning herself to the spartacus variable. Only one
    variable is actually allowed to own an owned pointer, so ownership Moves to Wonder Woman moving it away from Spartacus. So now Wonder Woman
    gets to be Spartacus!

    View full-size slide

  46. fn main() {
    let spartacus = ~"Spartacus";
    println!("I'm {:?}!", spartacus);
    !
    let wonder_woman = spartacus;
    println!("No, I'm {:?}!!", wonder_woman);
    }
    I'm ~"Spartacus"!
    No, I'm ~"Spartacus"!!
    Owned Pointers (~)
    Next up Wonder Woman steps in to take the rap. She takes ownership of the owned pointer by assigning herself to the spartacus variable. Only one
    variable is actually allowed to own an owned pointer, so ownership Moves to Wonder Woman moving it away from Spartacus. So now Wonder Woman
    gets to be Spartacus!

    View full-size slide

  47. fn main() {
    let spartacus = ~"Spartacus";
    println!("I'm {:?}!", spartacus);
    !
    let wonder_woman = spartacus;
    println!("No, I'm {:?}!!", wonder_woman);
    !
    let hulk = wonder_woman;
    println!("NO! HULK IS {:?}!!!", hulk);
    }
    Owned Pointers (~)
    Similarly Hulk in turn can also take over ownership of the owned pointer by taking it from Wonder Woman.
    !
    ‘NO! HULK IS ~”Spartacus”!!!’
    !
    Hulk really doesn’t get how this works…

    View full-size slide

  48. fn main() {
    let spartacus = ~"Spartacus";
    println!("I'm {:?}!", spartacus);
    !
    let wonder_woman = spartacus;
    println!("No, I'm {:?}!!", wonder_woman);
    !
    let hulk = wonder_woman;
    println!("NO! HULK IS {:?}!!!", hulk);
    }
    Owned Pointers (~)
    Similarly Hulk in turn can also take over ownership of the owned pointer by taking it from Wonder Woman.
    !
    ‘NO! HULK IS ~”Spartacus”!!!’
    !
    Hulk really doesn’t get how this works…

    View full-size slide

  49. fn main() {
    let spartacus = ~"Spartacus";
    println!("I'm {:?}!", spartacus);
    !
    let wonder_woman = spartacus;
    println!("No, I'm {:?}!!", wonder_woman);
    !
    let hulk = wonder_woman;
    println!("NO! HULK IS {:?}!!!", hulk);
    }
    I'm ~"Spartacus"!
    No, I'm ~"Spartacus"!!
    NO! HULK IS ~"Spartacus"!!!
    Owned Pointers (~)
    Similarly Hulk in turn can also take over ownership of the owned pointer by taking it from Wonder Woman.
    !
    ‘NO! HULK IS ~”Spartacus”!!!’
    !
    Hulk really doesn’t get how this works…

    View full-size slide

  50. fn main() {
    let spartacus = ~"Spartacus";
    println!("I'm {:s}!", spartacus);
    !
    let wonder_woman = spartacus;
    println!("No, I'm {:s}!!", wonder_woman);
    !
    let hulk = wonder_woman;
    println!("NO! HULK IS {:s}!!!", hulk);
    }
    I'm Spartacus!!
    No, I'm Spartacus!!!
    NO! HULK IS Spartacus!!!
    Owned Pointers (~)
    I think we’ve made it pretty clear that we’re outputting owned strings, so I’m going to switch out the output to plain strings. Much cleaner!

    View full-size slide

  51. fn main() {
    let spartacus = ~"Spartacus";
    println!("I'm {:s}!", spartacus);
    !
    let wonder_woman = spartacus;
    println!("No, I'm {:s}!!", wonder_woman);
    !
    let hulk = wonder_woman;
    println!("NO! HULK IS {:s}!!!", hulk);
    !
    println!("No really, I am {:s} :(", spartacus);
    }
    Owned Pointers (~)
    Spartacus at this point tries to set everyone straight. But because ownership of ~”Spartacus” has moved, accessing the spartacus variable is doomed to
    compiler failure.

    View full-size slide

  52. fn main() {
    let spartacus = ~"Spartacus";
    println!("I'm {:s}!", spartacus);
    !
    let wonder_woman = spartacus;
    println!("No, I'm {:s}!!", wonder_woman);
    !
    let hulk = wonder_woman;
    println!("NO! HULK IS {:s}!!!", hulk);
    !
    println!("No really, I am {:s} :(", spartacus);
    }
    spartacus.rs:11:39: 11:48 error: use of moved value: `spartacus`
    spartacus.rs:11 println!("No really, I am {:s}!", spartacus);
    ^~~~~~~~~
    Owned Pointers (~)
    Spartacus at this point tries to set everyone straight. But because ownership of ~”Spartacus” has moved, accessing the spartacus variable is doomed to
    compiler failure.

    View full-size slide

  53. fn main() {
    let spartacus = "Spartacus";
    println!("I'm {:s}!", spartacus);
    !
    let wonder_woman = spartacus;
    println!("No, I'm {:s}!!", wonder_woman);
    !
    let hulk = wonder_woman;
    println!("NO! HULK IS {:s}!!!", hulk);
    !
    println!("No really, I am {:s} :(", spartacus);
    }
    Owned Pointers (~)
    Of course we could just declare a normal string instead of an “owned” string. The we would be passing around a reference pointer which would not get
    moved. We would be subject to Borrowing restrictions rather than Moving restrictions.
    Of course they’re all wrong…

    View full-size slide

  54. fn main() {
    let spartacus = "Spartacus";
    println!("I'm {:s}!", spartacus);
    !
    let wonder_woman = spartacus;
    println!("No, I'm {:s}!!", wonder_woman);
    !
    let hulk = wonder_woman;
    println!("NO! HULK IS {:s}!!!", hulk);
    !
    println!("No really, I am {:s} :(", spartacus);
    }
    I'm Spartacus!
    No, I'm Spartacus!!
    NO! HULK IS Spartacus!!!
    No really, I am Spartacus :(
    Owned Pointers (~)
    Of course we could just declare a normal string instead of an “owned” string. The we would be passing around a reference pointer which would not get
    moved. We would be subject to Borrowing restrictions rather than Moving restrictions.
    Of course they’re all wrong…

    View full-size slide

  55. Of course they’re all wrong. Morpheus is Spartacus

    View full-size slide

  56. Of course they’re all wrong. Morpheus is Spartacus

    View full-size slide

  57. struct Liberator {
    name: ~str,
    favorite_color: &'static str
    }
    !
    fn defiance(prefix: &str, liberator: &mut Liberator) {
    liberator.name.push_char('!');
    println!("{:s} {:s}", prefix, liberator.name);
    }
    !
    fn main() {
    let mut spartacus = ~Liberator { name: ~"Spartacus",
    favorite_color: "chartreuse" };
    defiance("I'm", spartacus);
    !
    let mut wonder_woman = spartacus;
    defiance("No I'm", wonder_woman);
    !
    let mut hulk = wonder_woman;
    defiance("NO! HULK IS", hulk);
    }
    Let’s throw something new into the mix: structs. I declare a liberator struct at the top here. I’ve decided the name is like before, an owned string, but for
    the favorite color I just decided to keep it static. Because I’m effectively borrowing a static value in a struct like this the compiler needs some kind of clue
    about how long lived it is, so I add the special lifetime type, ‘static, which lasts the length of the application.
    !
    When I assign spartacus to an instance of Liberator I have to declare all the struct's properties (name and favorite_color). Yes, Spartacus’ favorite color is
    chartreuse. Not many people know that.
    !
    I’ve also brought in a function, defiance() to handle all that glorious shouting. In the definition of defiance() we’re receiving the arguments as references.
    These parameters finish borrowing when the function has completed, so borrowing works pretty well here. I’m defined the liberator parameter as mutable
    so we can add extra exclamation marks to the name.
    !
    End results: same results as before. This is just a refactor.

    View full-size slide

  58. struct Liberator {
    name: ~str,
    favorite_color: &'static str
    }
    !
    fn defiance(prefix: &str, liberator: &mut Liberator) {
    liberator.name.push_char('!');
    println!("{:s} {:s}", prefix, liberator.name);
    }
    !
    fn main() {
    let mut spartacus = ~Liberator { name: ~"Spartacus",
    favorite_color: "chartreuse" };
    defiance("I'm", spartacus);
    !
    let mut wonder_woman = spartacus;
    defiance("No I'm", wonder_woman);
    !
    let mut hulk = wonder_woman;
    defiance("NO! HULK IS", hulk);
    }
    Let’s throw something new into the mix: structs. I declare a liberator struct at the top here. I’ve decided the name is like before, an owned string, but for
    the favorite color I just decided to keep it static. Because I’m effectively borrowing a static value in a struct like this the compiler needs some kind of clue
    about how long lived it is, so I add the special lifetime type, ‘static, which lasts the length of the application.
    !
    When I assign spartacus to an instance of Liberator I have to declare all the struct's properties (name and favorite_color). Yes, Spartacus’ favorite color is
    chartreuse. Not many people know that.
    !
    I’ve also brought in a function, defiance() to handle all that glorious shouting. In the definition of defiance() we’re receiving the arguments as references.
    These parameters finish borrowing when the function has completed, so borrowing works pretty well here. I’m defined the liberator parameter as mutable
    so we can add extra exclamation marks to the name.
    !
    End results: same results as before. This is just a refactor.

    View full-size slide

  59. struct Liberator {
    name: ~str,
    favorite_color: &'static str
    }
    !
    fn defiance(prefix: &str, liberator: &mut Liberator) {
    liberator.name.push_char('!');
    println!("{:s} {:s}", prefix, liberator.name);
    }
    !
    fn main() {
    let mut spartacus = ~Liberator { name: ~"Spartacus",
    favorite_color: "chartreuse" };
    defiance("I'm", spartacus);
    !
    let mut wonder_woman = spartacus;
    defiance("No I'm", wonder_woman);
    !
    let mut hulk = wonder_woman;
    defiance("NO! HULK IS", hulk);
    }
    Let’s throw something new into the mix: structs. I declare a liberator struct at the top here. I’ve decided the name is like before, an owned string, but for
    the favorite color I just decided to keep it static. Because I’m effectively borrowing a static value in a struct like this the compiler needs some kind of clue
    about how long lived it is, so I add the special lifetime type, ‘static, which lasts the length of the application.
    !
    When I assign spartacus to an instance of Liberator I have to declare all the struct's properties (name and favorite_color). Yes, Spartacus’ favorite color is
    chartreuse. Not many people know that.
    !
    I’ve also brought in a function, defiance() to handle all that glorious shouting. In the definition of defiance() we’re receiving the arguments as references.
    These parameters finish borrowing when the function has completed, so borrowing works pretty well here. I’m defined the liberator parameter as mutable
    so we can add extra exclamation marks to the name.
    !
    End results: same results as before. This is just a refactor.

    View full-size slide

  60. struct Liberator {
    name: ~str,
    favorite_color: &'static str
    }
    !
    fn defiance(prefix: &str, liberator: &mut Liberator) {
    liberator.name.push_char('!');
    println!("{:s} {:s}", prefix, liberator.name);
    }
    !
    fn main() {
    let mut spartacus = ~Liberator { name: ~"Spartacus",
    favorite_color: "chartreuse" };
    defiance("I'm", spartacus);
    !
    let mut wonder_woman = spartacus;
    defiance("No I'm", wonder_woman);
    !
    let mut hulk = wonder_woman;
    defiance("NO! HULK IS", hulk);
    }
    Let’s throw something new into the mix: structs. I declare a liberator struct at the top here. I’ve decided the name is like before, an owned string, but for
    the favorite color I just decided to keep it static. Because I’m effectively borrowing a static value in a struct like this the compiler needs some kind of clue
    about how long lived it is, so I add the special lifetime type, ‘static, which lasts the length of the application.
    !
    When I assign spartacus to an instance of Liberator I have to declare all the struct's properties (name and favorite_color). Yes, Spartacus’ favorite color is
    chartreuse. Not many people know that.
    !
    I’ve also brought in a function, defiance() to handle all that glorious shouting. In the definition of defiance() we’re receiving the arguments as references.
    These parameters finish borrowing when the function has completed, so borrowing works pretty well here. I’m defined the liberator parameter as mutable
    so we can add extra exclamation marks to the name.
    !
    End results: same results as before. This is just a refactor.

    View full-size slide

  61. struct Liberator {
    name: ~str,
    favorite_color: &'static str
    }
    !
    fn defiance(prefix: &str, liberator: &mut Liberator) {
    liberator.name.push_char('!');
    println!("{:s} {:s}", prefix, liberator.name);
    }
    !
    fn main() {
    let mut spartacus = ~Liberator { name: ~"Spartacus",
    favorite_color: "chartreuse" };
    defiance("I'm", spartacus);
    !
    let mut wonder_woman = spartacus;
    defiance("No I'm", wonder_woman);
    !
    let mut hulk = wonder_woman;
    defiance("NO! HULK IS", hulk);
    }
    Let’s throw something new into the mix: structs. I declare a liberator struct at the top here. I’ve decided the name is like before, an owned string, but for
    the favorite color I just decided to keep it static. Because I’m effectively borrowing a static value in a struct like this the compiler needs some kind of clue
    about how long lived it is, so I add the special lifetime type, ‘static, which lasts the length of the application.
    !
    When I assign spartacus to an instance of Liberator I have to declare all the struct's properties (name and favorite_color). Yes, Spartacus’ favorite color is
    chartreuse. Not many people know that.
    !
    I’ve also brought in a function, defiance() to handle all that glorious shouting. In the definition of defiance() we’re receiving the arguments as references.
    These parameters finish borrowing when the function has completed, so borrowing works pretty well here. I’m defined the liberator parameter as mutable
    so we can add extra exclamation marks to the name.
    !
    End results: same results as before. This is just a refactor.

    View full-size slide

  62. struct Liberator {
    name: ~str,
    favorite_color: &'static str
    }
    !
    fn defiance(prefix: &str, liberator: &mut Liberator) {
    liberator.name.push_char('!');
    println!("{:s} {:s}", prefix, liberator.name);
    }
    !
    fn main() {
    let mut spartacus = ~Liberator { name: ~"Spartacus",
    favorite_color: "chartreuse" };
    defiance("I'm", spartacus);
    !
    let mut wonder_woman = spartacus;
    defiance("No I'm", wonder_woman);
    !
    let mut hulk = wonder_woman;
    defiance("NO! HULK IS", hulk);
    }
    I'm Spartacus!
    No I'm Spartacus!!
    NO! HULK IS Spartacus!!!
    Let’s throw something new into the mix: structs. I declare a liberator struct at the top here. I’ve decided the name is like before, an owned string, but for
    the favorite color I just decided to keep it static. Because I’m effectively borrowing a static value in a struct like this the compiler needs some kind of clue
    about how long lived it is, so I add the special lifetime type, ‘static, which lasts the length of the application.
    !
    When I assign spartacus to an instance of Liberator I have to declare all the struct's properties (name and favorite_color). Yes, Spartacus’ favorite color is
    chartreuse. Not many people know that.
    !
    I’ve also brought in a function, defiance() to handle all that glorious shouting. In the definition of defiance() we’re receiving the arguments as references.
    These parameters finish borrowing when the function has completed, so borrowing works pretty well here. I’m defined the liberator parameter as mutable
    so we can add extra exclamation marks to the name.
    !
    End results: same results as before. This is just a refactor.

    View full-size slide

  63. struct Liberator {
    name: ~str,
    favorite_color: &'static str
    }
    !
    impl Liberator {
    fn defiance(&mut self, prefix: &str) {
    self.name.push_char('!');
    println!("{:s} {:s}", prefix, self.name);
    }
    }
    !
    fn main() {
    let mut spartacus = ~Liberator { name: ~"Spartacus",
    favorite_color: "chartreuse" };
    spartacus.defiance("I'm");
    !
    let mut wonder_woman = spartacus;
    wonder_woman.defiance("No I'm");
    !
    let mut hulk = wonder_woman;
    hulk.defiance("NO! HULK IS");
    }
    I'm Spartacus!!
    No I'm Spartacus!!!
    NO! HULK IS Spartacus!!!
    Defiance really feels like it should be a method of Liberator. We can do that by declaring an impl block for Liberator.
    !
    When calling defiance we just pass one argument now, covering the preamble (“I’m”, “No I’m”, “NO! HULK IS”, etc).
    !
    When we define the function we have to declare an extra parameter called ‘self’. This is used to self reference inside the function. Kind of similar to how
    python declares methods. One difference with python though, you add modifiers like &, ~ and mut depending on how self is being accessed. In this we
    going with &mut so we can can change the name property.

    View full-size slide

  64. struct Liberator {
    name: ~str,
    favorite_color: &'static str
    }
    !
    impl Liberator {
    fn defiance(&mut self, prefix: &str) {
    self.name.push_char('!');
    println!("{:s} {:s}", prefix, self.name);
    }
    }
    !
    fn main() {
    let mut spartacus = ~Liberator { name: ~"Spartacus",
    favorite_color: "chartreuse" };
    spartacus.defiance("I'm");
    !
    let mut wonder_woman = spartacus;
    wonder_woman.defiance("No I'm");
    !
    let mut hulk = wonder_woman;
    hulk.defiance("NO! HULK IS");
    }
    I'm Spartacus!!
    No I'm Spartacus!!!
    NO! HULK IS Spartacus!!!
    Defiance really feels like it should be a method of Liberator. We can do that by declaring an impl block for Liberator.
    !
    When calling defiance we just pass one argument now, covering the preamble (“I’m”, “No I’m”, “NO! HULK IS”, etc).
    !
    When we define the function we have to declare an extra parameter called ‘self’. This is used to self reference inside the function. Kind of similar to how
    python declares methods. One difference with python though, you add modifiers like &, ~ and mut depending on how self is being accessed. In this we
    going with &mut so we can can change the name property.

    View full-size slide

  65. struct Liberator {
    name: ~str,
    favorite_color: &'static str
    }
    !
    impl Liberator {
    fn defiance(&mut self, prefix: &str) {
    self.name.push_char('!');
    println!("{:s} {:s}", prefix, self.name);
    }
    }
    !
    fn main() {
    let mut spartacus = ~Liberator { name: ~"Spartacus",
    favorite_color: "chartreuse" };
    spartacus.defiance("I'm");
    !
    let mut wonder_woman = spartacus;
    wonder_woman.defiance("No I'm");
    !
    let mut hulk = wonder_woman;
    hulk.defiance("NO! HULK IS");
    }
    I'm Spartacus!!
    No I'm Spartacus!!!
    NO! HULK IS Spartacus!!!
    Defiance really feels like it should be a method of Liberator. We can do that by declaring an impl block for Liberator.
    !
    When calling defiance we just pass one argument now, covering the preamble (“I’m”, “No I’m”, “NO! HULK IS”, etc).
    !
    When we define the function we have to declare an extra parameter called ‘self’. This is used to self reference inside the function. Kind of similar to how
    python declares methods. One difference with python though, you add modifiers like &, ~ and mut depending on how self is being accessed. In this we
    going with &mut so we can can change the name property.

    View full-size slide

  66. So… how about we do something useful with shared pointers? How about Linked Lists? For a pacman game…

    View full-size slide

  67. enum List{
    Node(~str, ~List),
    Nada
    }
    !
    fn main() {
    let blinky = ~Node(~"Blinky", ~Nada);
    let ghosts = blinky;
    }
    Building a Linked List
    We start off with a list of 1 item, the ghost Blinky. Blinky is defined using the Node tuple for defining a ghost name, and linking to the next link item.

    View full-size slide

  68. enum List{
    Node(~str, ~List),
    Nada
    }
    !
    fn main() {
    let blinky = ~Node(~"Blinky", ~Nada);
    let ghosts = blinky;
    }
    Building a Linked List
    Our list is terminated with a List token we created named “Nada”. There is no concept of null in Rust. Nulls lead to bugs so Rust stays clear of them.
    !
    Notice how Node and Nada are stored in a List enum? Enums in Rust are not limited to tokens or tokens with integer values. Our List enum used for each
    ghost gives us a choice between a Node tuple or a Nada terminator token.

    View full-size slide

  69. enum List{
    Node(~str, ~List),
    Nada
    }
    !
    impl List {
    fn announce(~self) {
    match *self {
    Node(name, next) => {
    println!("{:s} has entered the game!", name);
    next.announce();
    },
    Nada => ()
    }
    }
    }
    !
    fn main() {
    let blinky = ~Node(~"Blinky", ~Nada);
    let ghosts = blinky;
    !
    ghosts.announce();
    }
    Building a Linked List
    Might be nice if we did something with this linked list, so lets implement a method called announce() that shows which ghosts have entered the game.
    Yes, use of ‘impl' is not limited to just structs!
    !
    Our announce method is going to be called recursively. Borrowing isn’t going to be practical for this example, so we’ll define self as an owned pointer.
    !
    We need to access values in our List enum. For that we’ll use ‘match’ which is a bit like a case statement. When matching value ‘self’ points to
    (dereferenced using ‘*’ before self), we need entries that cover all enum variants.

    View full-size slide

  70. enum List{
    Node(~str, ~List),
    Nada
    }
    !
    impl List {
    fn announce(~self) {
    match *self {
    Node(name, next) => {
    println!("{:s} has entered the game!", name);
    next.announce();
    },
    Nada => ()
    }
    }
    }
    !
    fn main() {
    let blinky = ~Node(~"Blinky", ~Nada);
    let ghosts = blinky;
    !
    ghosts.announce();
    }
    Blinky has entered the game!
    Building a Linked List
    Might be nice if we did something with this linked list, so lets implement a method called announce() that shows which ghosts have entered the game.
    Yes, use of ‘impl' is not limited to just structs!
    !
    Our announce method is going to be called recursively. Borrowing isn’t going to be practical for this example, so we’ll define self as an owned pointer.
    !
    We need to access values in our List enum. For that we’ll use ‘match’ which is a bit like a case statement. When matching value ‘self’ points to
    (dereferenced using ‘*’ before self), we need entries that cover all enum variants.

    View full-size slide

  71. enum List{
    Node(~str, ~List),
    Nada
    }
    !
    impl List {
    fn announce(~self) {
    match *self {
    Node(name, next) => {
    println!("{:s} has entered the game!", name);
    next.announce();
    },
    Nada => ()
    }
    }
    }
    !
    fn main() {
    let blinky = ~Node(~"Blinky", ~Nada);
    let pinky = ~Node(~"Pinky", blinky);
    let ghosts = pinky;
    !
    ghosts.announce();
    }
    We can now Pinky to the linked list.

    View full-size slide

  72. enum List{
    Node(~str, ~List),
    Nada
    }
    !
    impl List {
    fn announce(~self) {
    match *self {
    Node(name, next) => {
    println!("{:s} has entered the game!", name);
    next.announce();
    },
    Nada => ()
    }
    }
    }
    !
    fn main() {
    let blinky = ~Node(~"Blinky", ~Nada);
    let pinky = ~Node(~"Pinky", blinky);
    let ghosts = pinky;
    !
    ghosts.announce();
    }
    We’ve tethered Pinky to Blinky like so…

    View full-size slide

  73. enum List{
    Node(~str, ~List),
    Nada
    }
    !
    impl List {
    fn announce(~self) {
    match *self {
    Node(name, next) => {
    println!("{:s} has entered the game!", name);
    next.announce();
    },
    Nada => ()
    }
    }
    }
    !
    fn main() {
    let blinky = ~Node(~"Blinky", ~Nada);
    let pinky = ~Node(~"Pinky", blinky);
    let ghosts = pinky;
    !
    ghosts.announce();
    }
    We’ve tethered Pinky to Blinky like so…

    View full-size slide

  74. enum List{
    Node(~str, ~List),
    Nada
    }
    !
    impl List {
    fn announce(~self) {
    match *self {
    Node(name, next) => {
    println!("{:s} has entered the game!", name);
    next.announce();
    },
    Nada => ()
    }
    }
    }
    !
    fn main() {
    let blinky = ~Node(~"Blinky", ~Nada);
    let pinky = ~Node(~"Pinky", blinky);
    let ghosts = pinky;
    !
    ghosts.announce();
    }
    Pinky has entered the game!
    Blinky has entered the game!
    We’ve tethered Pinky to Blinky like so…

    View full-size slide

  75. enum List{
    Node(~str, ~List),
    Nada
    }
    !
    impl List {
    fn announce(~self) {
    match *self {
    Node(name, next) => {
    println!("{:s} has entered the game!", name);
    next.announce();
    },
    Nada => ()
    }
    }
    }
    !
    fn main() {
    let blinky = ~Node(~"Blinky", ~Nada);
    let pinky = ~Node(~"Pinky", blinky);
    let inky = ~Node(~"Inky", pinky);
    let clyde = ~Node(~"Clyde", inky);
    let ghosts = clyde;
    !
    ghosts.announce();
    }
    And so on…

    View full-size slide

  76. enum List{
    Node(~str, ~List),
    Nada
    }
    !
    impl List {
    fn announce(~self) {
    match *self {
    Node(name, next) => {
    println!("{:s} has entered the game!", name);
    next.announce();
    },
    Nada => ()
    }
    }
    }
    !
    fn main() {
    let blinky = ~Node(~"Blinky", ~Nada);
    let pinky = ~Node(~"Pinky", blinky);
    let inky = ~Node(~"Inky", pinky);
    let clyde = ~Node(~"Clyde", inky);
    let ghosts = clyde;
    !
    ghosts.announce();
    }
    And so on…

    View full-size slide

  77. enum List{
    Node(~str, ~List),
    Nada
    }
    !
    impl List {
    fn announce(~self) {
    match *self {
    Node(name, next) => {
    println!("{:s} has entered the game!", name);
    next.announce();
    },
    Nada => ()
    }
    }
    }
    !
    fn main() {
    let blinky = ~Node(~"Blinky", ~Nada);
    let pinky = ~Node(~"Pinky", blinky);
    let inky = ~Node(~"Inky", pinky);
    let clyde = ~Node(~"Clyde", inky);
    let ghosts = clyde;
    !
    ghosts.announce();
    }
    Clyde has entered the game!
    Inky has entered the game!
    Pinky has entered the game!
    Blinky has entered the game!
    And so on…

    View full-size slide

  78. Rust has Generics. Also Traits. Let’s discuss further (I really want that mug…)

    View full-size slide

  79. struct Wotsit {
    item: int,
    description: ~str
    }
    !
    impl Wotsit {
    fn examine(&self) {
    println!("This wotsit is brought to you by the number {:d}",
    self.item);
    }
    }
    !
    fn main() {
    let the_answer = Wotsit {
    item: 42, description: ~"The ultimate answer"};
    the_answer.examine();
    }
    Generics and Traits
    Starting off, I’ve got a wotsit that can hold integer values. But I’d really like it to be able to contain anything.

    View full-size slide

  80. struct Wotsit {
    item: int,
    description: ~str
    }
    !
    impl Wotsit {
    fn examine(&self) {
    println!("This wotsit is brought to you by the number {:d}",
    self.item);
    }
    }
    !
    fn main() {
    let the_answer = Wotsit {
    item: 42, description: ~"The ultimate answer"};
    the_answer.examine();
    }
    This wotsit is brought to you by the number 42
    Generics and Traits
    Starting off, I’ve got a wotsit that can hold integer values. But I’d really like it to be able to contain anything.

    View full-size slide

  81. struct Wotsit {
    item: T,
    description: ~str
    }
    !
    impl Wotsit {
    fn examine(&self) {
    println!("This wotsit is brought to you by the number {:d}",
    self.item);
    }
    }
    !
    fn main() {
    let the_answer = Wotsit {
    item: 42, description: ~"The ultimate answer"};
    the_answer.examine();
    }
    Generics and Traits
    So I’ve tweaked the struct a little so it accepts any type. A consequence of this Wotsit implementation is no longer good. Its designed to work for integers
    only

    View full-size slide

  82. struct Wotsit {
    item: T,
    description: ~str
    }
    !
    trait Viewable{
    fn examine(&self) {
    println!("This wotsit contains... you know... thingies");
    }
    }
    !
    impl Viewable for Wotsit {}
    !
    fn main() {
    let the_answer = Wotsit {
    item: 42, description: ~"The ultimate answer"};
    the_answer.examine();
    }
    Generics and Traits
    So to deal with these type specific implementations I’ve implemented a trait called Viewable. Viewable is defined now for integer Wotsits. I’ve given
    Viewable a default for the examine function that prints this really vague piece of information…

    View full-size slide

  83. struct Wotsit {
    item: T,
    description: ~str
    }
    !
    trait Viewable{
    fn examine(&self) {
    println!("This wotsit contains... you know... thingies");
    }
    }
    !
    impl Viewable for Wotsit {}
    !
    fn main() {
    let the_answer = Wotsit {
    item: 42, description: ~"The ultimate answer"};
    the_answer.examine();
    }
    Generics and Traits
    So to deal with these type specific implementations I’ve implemented a trait called Viewable. Viewable is defined now for integer Wotsits. I’ve given
    Viewable a default for the examine function that prints this really vague piece of information…

    View full-size slide

  84. struct Wotsit {
    item: T,
    description: ~str
    }
    !
    trait Viewable{
    fn examine(&self) {
    println!("This wotsit contains... you know... thingies");
    }
    }
    !
    impl Viewable for Wotsit {}
    !
    fn main() {
    let the_answer = Wotsit {
    item: 42, description: ~"The ultimate answer"};
    the_answer.examine();
    }
    This wotsit contains... you know... thingies
    Generics and Traits
    So to deal with these type specific implementations I’ve implemented a trait called Viewable. Viewable is defined now for integer Wotsits. I’ve given
    Viewable a default for the examine function that prints this really vague piece of information…

    View full-size slide

  85. struct Wotsit {
    item: T,
    description: ~str
    }
    !
    trait Viewable{
    fn examine(&self) {
    println!("This wotsit contains... you know... thingies");
    }
    }
    !
    impl Viewable for Wotsit {
    fn examine(&self) {
    println!("This wotsit is brought to you by the number {:d}",
    self.item);
    }
    }
    !
    fn main() {
    let the_answer = Wotsit {
    item: 42, description: ~"The ultimate answer"};
    the_answer.examine();
    }
    That’s a bit too vague, so we’ll just override the examine method for integer Wotsits.

    View full-size slide

  86. struct Wotsit {
    item: T,
    description: ~str
    }
    !
    trait Viewable{
    fn examine(&self) {
    println!("This wotsit contains... you know... thingies");
    }
    }
    !
    impl Viewable for Wotsit {
    fn examine(&self) {
    println!("This wotsit is brought to you by the number {:d}",
    self.item);
    }
    }
    !
    fn main() {
    let the_answer = Wotsit {
    item: 42, description: ~"The ultimate answer"};
    the_answer.examine();
    }
    This wotsit is brought to you by the number 42
    That’s a bit too vague, so we’ll just override the examine method for integer Wotsits.

    View full-size slide

  87. struct Wotsit {
    item: T,
    description: ~str
    }
    !
    trait Viewable{
    fn examine(&self) {
    println!("This wotsit contains... you know... thingies");
    }
    }
    !
    impl Viewable for Wotsit {
    fn examine(&self) {
    println!("This wotsit is brought to you by the number {:d}",
    self.item);
    }
    }
    !
    impl Viewable for Wotsit<~str> {
    fn examine(&self) {
    println!("This wotsit contains a '{:s}'", self.item);
    }
    }
    !
    fn main() {
    let the_answer = Wotsit {
    item: 42, description: ~"The ultimate answer"};
    the_answer.examine();
    let power_cell = Wotsit {
    item: ~"confused cat", description: ~"Powers the internet"};
    power_cell.examine();
    }
    … and lets expand it’s capabilities to actor for owned strings….

    View full-size slide

  88. struct Wotsit {
    item: T,
    description: ~str
    }
    !
    trait Viewable{
    fn examine(&self) {
    println!("This wotsit contains... you know... thingies");
    }
    }
    !
    impl Viewable for Wotsit {
    fn examine(&self) {
    println!("This wotsit is brought to you by the number {:d}",
    self.item);
    }
    }
    !
    impl Viewable for Wotsit<~str> {
    fn examine(&self) {
    println!("This wotsit contains a '{:s}'", self.item);
    }
    }
    !
    fn main() {
    let the_answer = Wotsit {
    item: 42, description: ~"The ultimate answer"};
    the_answer.examine();
    let power_cell = Wotsit {
    item: ~"confused cat", description: ~"Powers the internet"};
    power_cell.examine();
    }
    … and lets expand it’s capabilities to actor for owned strings….

    View full-size slide

  89. struct Wotsit {
    item: T,
    description: ~str
    }
    !
    trait Viewable{
    fn examine(&self) {
    println!("This wotsit contains... you know... thingies");
    }
    }
    !
    impl Viewable for Wotsit {
    fn examine(&self) {
    println!("This wotsit is brought to you by the number {:d}",
    self.item);
    }
    }
    !
    impl Viewable for Wotsit<~str> {
    fn examine(&self) {
    println!("This wotsit contains a '{:s}'", self.item);
    }
    }
    !
    fn main() {
    let the_answer = Wotsit {
    item: 42, description: ~"The ultimate answer"};
    the_answer.examine();
    let power_cell = Wotsit {
    item: ~"confused cat", description: ~"Powers the internet"};
    power_cell.examine();
    }
    … and lets expand it’s capabilities to actor for owned strings….

    View full-size slide

  90. struct Wotsit {
    item: T,
    description: ~str
    }
    !
    trait Viewable{
    fn examine(&self) {
    println!("This wotsit contains... you know... thingies");
    }
    }
    !
    impl Viewable for Wotsit {
    fn examine(&self) {
    println!("This wotsit is brought to you by the number {:d}",
    self.item);
    }
    }
    !
    impl Viewable for Wotsit<~str> {
    fn examine(&self) {
    println!("This wotsit contains a '{:s}'", self.item);
    }
    }
    !
    fn main() {
    let the_answer = Wotsit {
    item: 42, description: ~"The ultimate answer"};
    the_answer.examine();
    let power_cell = Wotsit {
    item: ~"confused cat", description: ~"Powers the internet"};
    power_cell.examine();
    }
    This wotsit is brought to you by the number 42
    This wotsit contains a 'confused cat'
    … and lets expand it’s capabilities to actor for owned strings….

    View full-size slide

  91. Let’s talk about closures!

    View full-size slide

  92. fn(x) {
    !
    }
    counter += counter + x;
    1) For those of you need reminding, a closure is typically an anonymous function that
    2) can influence variable outside of it’s internal scope. So that each time you call it can change state. So in this example the closure is updating the outer
    counter variable each time it gets run.
    3) Although of course closures in Rust look more like ruby blocks.

    View full-size slide

  93. fn(x) {
    !
    }
    Function Scope
    Outer
    let mut counter = 4;
    counter += counter + x;
    1) For those of you need reminding, a closure is typically an anonymous function that
    2) can influence variable outside of it’s internal scope. So that each time you call it can change state. So in this example the closure is updating the outer
    counter variable each time it gets run.
    3) Although of course closures in Rust look more like ruby blocks.

    View full-size slide

  94. Function Scope
    Outer
    let mut counter = 4;
    counter += counter + x;
    let closure = |x| {
    !
    }
    !
    !
    1) For those of you need reminding, a closure is typically an anonymous function that
    2) can influence variable outside of it’s internal scope. So that each time you call it can change state. So in this example the closure is updating the outer
    counter variable each time it gets run.
    3) Although of course closures in Rust look more like ruby blocks.

    View full-size slide

  95. use std::io::timer::sleep;
    !
    // Rust 0.10
    fn main() {
    let actions = [("Captain America", "bashes", 20),
    ("Black Widow", "slashes", 25),
    ("Ironman", "throws cash at", 0),
    ("Hulk", "SMASHES", 200)];
    !
    let mut outcomes =
    actions.iter()
    .map(|&action| {
    let (hero, attack, damage) = action;
    format!("{:s} {:s} Red Skull for {:d} damage",
    hero, attack, damage)
    });
    !
    for outcome in outcomes {
    spawn(proc() {
    sleep(500);
    println!(“{:s}”, outcome);
    });
    }
    }
    Closures
    As you may remember we used closures earlier in the map function for building outcome strings. And also for spawning tasks.

    View full-size slide

  96. use std::io::timer::sleep;
    !
    // Rust 0.10
    fn main() {
    let actions = [("Captain America", "bashes", 20),
    ("Black Widow", "slashes", 25),
    ("Ironman", "throws cash at", 0),
    ("Hulk", "SMASHES", 200)];
    !
    let mut outcomes =
    actions.iter()
    .map(|&action| {
    let (hero, attack, damage) = action;
    format!("{:s} {:s} Red Skull for {:d} damage",
    hero, attack, damage)
    });
    !
    for outcome in outcomes {
    spawn(proc() {
    sleep(500);
    println!(“{:s}”, outcome);
    });
    }
    }
    Closures
    As you may remember we used closures earlier in the map function for building outcome strings. And also for spawning tasks.

    View full-size slide

  97. fn main() {
    let mut outer_value = 0;
    !
    let increment = |x| {
    outer_value += x;
    };
    !
    increment(7);
    println!("outer_value now equals {:d}", outer_value);
    }
    Closures
    Let’s play! To start off with we have a simple “increment” closure. We execute it with an argument of 7. Inside the closure x will equal 7, which gets added
    onto the outer_value.

    View full-size slide

  98. fn main() {
    let mut outer_value = 0;
    !
    let increment = |x| {
    outer_value += x;
    };
    !
    increment(7);
    println!("outer_value now equals {:d}", outer_value);
    }
    outer_value now equals 7
    Closures
    Let’s play! To start off with we have a simple “increment” closure. We execute it with an argument of 7. Inside the closure x will equal 7, which gets added
    onto the outer_value.

    View full-size slide

  99. fn transform(mutator: |int| -> int, value: int ) {
    let result = mutator(value);
    println!("outer_value now equals {:d}", result);
    }
    !
    fn main() {
    let mut outer_value = 0;
    !
    let increment = |x| {
    outer_value += x;
    outer_value
    };
    !
    transform(increment, 7);
    }
    outer_value now equals 7
    We can pass this closure into a function as an argument. Transform will accept any closure along with an input value. So again we get 7.

    View full-size slide

  100. fn transform(mutator: |int| -> int, value: int ) {
    let result = mutator(value);
    println!("outer_value now equals {:d}", result);
    }
    !
    fn main() {
    let mut outer_value = 0;
    !
    let increment = |x| {
    outer_value += x;
    outer_value
    };
    !
    transform(increment, 7);
    transform(increment, 35);
    }
    As I mentioned earlier, we expect closures to continually change state. Lets test that by transforming increment twice. This doesn’t go so well. The
    problem is we passed the closure as what’s known as a stack closure. A closure defined on the stack. When it got passed in the ownership moved making
    it unsafe to call twice. The compiler has actually told us how to work around this though. We just have to wrap the stack closure in another closure as we
    call it.

    View full-size slide

  101. fn transform(mutator: |int| -> int, value: int ) {
    let result = mutator(value);
    println!("outer_value now equals {:d}", result);
    }
    !
    fn main() {
    let mut outer_value = 0;
    !
    let increment = |x| {
    outer_value += x;
    outer_value
    };
    !
    transform(increment, 7);
    transform(increment, 35);
    }
    closures.rs:15:15: 15:24 error: use of moved value: `increment`
    closures.rs:15 transform(increment, 35);
    ^~~~~~~~~
    closures.rs:14:15: 14:24 note: `increment` moved here because it has type `|int| -> int`, which
    is a non-copyable stack closure (capture it in a new closure, e.g. `|x| f(x)`, to override)
    closures.rs:14 transform(increment, 7);
    ^~~~~~~~~
    As I mentioned earlier, we expect closures to continually change state. Lets test that by transforming increment twice. This doesn’t go so well. The
    problem is we passed the closure as what’s known as a stack closure. A closure defined on the stack. When it got passed in the ownership moved making
    it unsafe to call twice. The compiler has actually told us how to work around this though. We just have to wrap the stack closure in another closure as we
    call it.

    View full-size slide

  102. fn transform(mutator: |int| -> int, value: int ) {
    let result = mutator(value);
    println!("outer_value now equals {:d}", result);
    }
    !
    fn main() {
    let mut outer_value = 0;
    !
    let increment = |x| {
    outer_value += x;
    outer_value
    };
    !
    transform(|x| { increment(x) }, 7);
    transform(|x| { increment(x) }, 35);
    }
    So now we wrap increment in a closure as we call transform and all is good!

    View full-size slide

  103. fn transform(mutator: |int| -> int, value: int ) {
    let result = mutator(value);
    println!("outer_value now equals {:d}", result);
    }
    !
    fn main() {
    let mut outer_value = 0;
    !
    let increment = |x| {
    outer_value += x;
    outer_value
    };
    !
    transform(|x| { increment(x) }, 7);
    transform(|x| { increment(x) }, 35);
    }
    outer_value now equals 7
    outer_value now equals 42
    So now we wrap increment in a closure as we call transform and all is good!

    View full-size slide

  104. fn transform(mutator: |int| -> int, value: int ) {
    let result = mutator(value);
    println!(“ outer_value now equals {:d}", result);
    }
    !
    fn main() {
    let mut outer_inc_value = 0;
    let increment = |x| {
    outer_inc_value += x;
    outer_inc_value
    };
    !
    let mut outer_mul_value = 1;
    let multiply = |x| {
    outer_mul_value *= x;
    outer_mul_value
    };
    !
    println!(“Additions:");
    transform(|x| { increment(x) }, 7);
    transform(|x| { increment(x) }, 35);
    !
    println!(“Multiplications:");
    transform(|x| { multiply(x) }, 5);
    transform(|x| { multiply(x) }, 3);
    }
    I mentioned earlier that transform can take any closure as an input, as long as it contains a single argument. So lets try a multiplication closure…

    View full-size slide

  105. fn transform(mutator: |int| -> int, value: int ) {
    let result = mutator(value);
    println!(“ outer_value now equals {:d}", result);
    }
    !
    fn main() {
    let mut outer_inc_value = 0;
    let increment = |x| {
    outer_inc_value += x;
    outer_inc_value
    };
    !
    let mut outer_mul_value = 1;
    let multiply = |x| {
    outer_mul_value *= x;
    outer_mul_value
    };
    !
    println!(“Additions:");
    transform(|x| { increment(x) }, 7);
    transform(|x| { increment(x) }, 35);
    !
    println!(“Multiplications:");
    transform(|x| { multiply(x) }, 5);
    transform(|x| { multiply(x) }, 3);
    }
    Additions:
    outer_value now equals 7
    outer_value now equals 42
    Multiplications:
    outer_value now equals 5
    outer_value now equals 15
    I mentioned earlier that transform can take any closure as an input, as long as it contains a single argument. So lets try a multiplication closure…

    View full-size slide

  106. Rust is really good at concurrency. Lets talk about that!

    View full-size slide

  107. Rust is really good at concurrency. Lets talk about that!

    View full-size slide

  108. Tasks
    Rust use the CSP model of concurrency. Which stands for Communicating Sequential Processes. Using this model rust threads (know as Tasks) can
    communicate through channels or pipes. When creating the simplest variant, a “Sender” variable is provided for sending information and a “Port” variable
    is provided for receiving. So now Task A can send a message to Task B asynchronously despite being on a different thread. Task B listens by calling the
    recv() method. Task A sends data using the send() method. The companion cube has just sent a little heart to the cake.
    !
    This is just the simplest type of channel. For example duplex channels are also available in Rust for sending both ways.

    View full-size slide

  109. Tasks
    CSP - Communicating Sequential Processes
    Rust use the CSP model of concurrency. Which stands for Communicating Sequential Processes. Using this model rust threads (know as Tasks) can
    communicate through channels or pipes. When creating the simplest variant, a “Sender” variable is provided for sending information and a “Port” variable
    is provided for receiving. So now Task A can send a message to Task B asynchronously despite being on a different thread. Task B listens by calling the
    recv() method. Task A sends data using the send() method. The companion cube has just sent a little heart to the cake.
    !
    This is just the simplest type of channel. For example duplex channels are also available in Rust for sending both ways.

    View full-size slide

  110. Tasks
    CSP - Communicating Sequential Processes
    Rust use the CSP model of concurrency. Which stands for Communicating Sequential Processes. Using this model rust threads (know as Tasks) can
    communicate through channels or pipes. When creating the simplest variant, a “Sender” variable is provided for sending information and a “Port” variable
    is provided for receiving. So now Task A can send a message to Task B asynchronously despite being on a different thread. Task B listens by calling the
    recv() method. Task A sends data using the send() method. The companion cube has just sent a little heart to the cake.
    !
    This is just the simplest type of channel. For example duplex channels are also available in Rust for sending both ways.

    View full-size slide

  111. Tasks
    CSP - Communicating Sequential Processes
    Sender<~str>
    Task A
    Rust use the CSP model of concurrency. Which stands for Communicating Sequential Processes. Using this model rust threads (know as Tasks) can
    communicate through channels or pipes. When creating the simplest variant, a “Sender” variable is provided for sending information and a “Port” variable
    is provided for receiving. So now Task A can send a message to Task B asynchronously despite being on a different thread. Task B listens by calling the
    recv() method. Task A sends data using the send() method. The companion cube has just sent a little heart to the cake.
    !
    This is just the simplest type of channel. For example duplex channels are also available in Rust for sending both ways.

    View full-size slide

  112. Tasks
    CSP - Communicating Sequential Processes
    Sender<~str>
    Task A
    Receiver<~str>
    Task B
    Rust use the CSP model of concurrency. Which stands for Communicating Sequential Processes. Using this model rust threads (know as Tasks) can
    communicate through channels or pipes. When creating the simplest variant, a “Sender” variable is provided for sending information and a “Port” variable
    is provided for receiving. So now Task A can send a message to Task B asynchronously despite being on a different thread. Task B listens by calling the
    recv() method. Task A sends data using the send() method. The companion cube has just sent a little heart to the cake.
    !
    This is just the simplest type of channel. For example duplex channels are also available in Rust for sending both ways.

    View full-size slide

  113. Tasks
    println(receiver.recv());
    CSP - Communicating Sequential Processes
    Sender<~str>
    Task A
    Receiver<~str>
    Task B
    Rust use the CSP model of concurrency. Which stands for Communicating Sequential Processes. Using this model rust threads (know as Tasks) can
    communicate through channels or pipes. When creating the simplest variant, a “Sender” variable is provided for sending information and a “Port” variable
    is provided for receiving. So now Task A can send a message to Task B asynchronously despite being on a different thread. Task B listens by calling the
    recv() method. Task A sends data using the send() method. The companion cube has just sent a little heart to the cake.
    !
    This is just the simplest type of channel. For example duplex channels are also available in Rust for sending both ways.

    View full-size slide

  114. Tasks
    sender.send(“<3!”); println(receiver.recv());
    CSP - Communicating Sequential Processes
    Sender<~str>
    Task A
    Receiver<~str>
    Task B
    Rust use the CSP model of concurrency. Which stands for Communicating Sequential Processes. Using this model rust threads (know as Tasks) can
    communicate through channels or pipes. When creating the simplest variant, a “Sender” variable is provided for sending information and a “Port” variable
    is provided for receiving. So now Task A can send a message to Task B asynchronously despite being on a different thread. Task B listens by calling the
    recv() method. Task A sends data using the send() method. The companion cube has just sent a little heart to the cake.
    !
    This is just the simplest type of channel. For example duplex channels are also available in Rust for sending both ways.

    View full-size slide

  115. Tasks
    sender.send(“<3!”); println(receiver.recv());
    <3!
    CSP - Communicating Sequential Processes
    Sender<~str>
    Task A
    Receiver<~str>
    Task B
    Rust use the CSP model of concurrency. Which stands for Communicating Sequential Processes. Using this model rust threads (know as Tasks) can
    communicate through channels or pipes. When creating the simplest variant, a “Sender” variable is provided for sending information and a “Port” variable
    is provided for receiving. So now Task A can send a message to Task B asynchronously despite being on a different thread. Task B listens by calling the
    recv() method. Task A sends data using the send() method. The companion cube has just sent a little heart to the cake.
    !
    This is just the simplest type of channel. For example duplex channels are also available in Rust for sending both ways.

    View full-size slide

  116. fn main() {
    let (sender, receiver) = channel();
    !
    spawn(proc() {
    sender.send("Marco!");
    sender.send("Pollooo!");
    });
    !
    for _ in range(0, 2) {
    println!("Got back '{}' from a rust task!”,
    receiver.recv());
    }
    }
    Tasks
    So here’s something similar as actual code. In this case we just have a single task created through the spawn function. It contains a proc, an owned closure.
    Because it’s a closure it can still access the chan variable despite it being in the other scope. In this case we’re just receiving the messages from the outer
    function itself. Note that in the for loop I didn’t actually need the variable containing the range number, so I just put in an underscore as a placeholder so
    we don’t get unused local variable warnings. Let’s add more tasks.

    View full-size slide

  117. fn main() {
    let (sender, receiver) = channel();
    !
    spawn(proc() {
    sender.send("Marco!");
    sender.send("Pollooo!");
    });
    !
    for _ in range(0, 2) {
    println!("Got back '{}' from a rust task!”,
    receiver.recv());
    }
    }
    Got back 'Marco!' from a rust task!
    Got back 'Pollooo!' from a rust task!
    Tasks
    So here’s something similar as actual code. In this case we just have a single task created through the spawn function. It contains a proc, an owned closure.
    Because it’s a closure it can still access the chan variable despite it being in the other scope. In this case we’re just receiving the messages from the outer
    function itself. Note that in the for loop I didn’t actually need the variable containing the range number, so I just put in an underscore as a placeholder so
    we don’t get unused local variable warnings. Let’s add more tasks.

    View full-size slide

  118. use std::ascii::StrAsciiExt;
    !
    fn main() {
    let (sender1, receiver1) = channel();
    let (sender2, receiver2) = channel();
    !
    sender1.send(~"ycnerrucnoc hcus");
    sender1.send(~"wow secar ynam");
    sender1.send(~"");
    !
    spawn(proc() {
    loop {
    let code = receiver1.recv();
    sender2.send(code.to_ascii_upper());
    if code == ~"" { break; }
    }
    });
    !
    spawn(proc() {
    loop {
    let code = receiver2.recv();
    if code == ~"" {
    break;
    } else {
    println!("Got back '{:s}'", code);
    }
    }
    });
    }
    In this sample we’re communicating directly between to tasks using 2 different channels. We use the first channel to send 2 encrypted messages to the
    first tasks which converts it to upper case and then relays it to a second task to output the results. For this setup you can keep sending messages until a
    blank message is received at which point the listeners quit. I’ve implemented the repeat until using loops and breaks. Most of the code inside the first task
    is just reading and writing to the channel. We could refactor that into another function.

    View full-size slide

  119. use std::ascii::StrAsciiExt;
    !
    fn main() {
    let (sender1, receiver1) = channel();
    let (sender2, receiver2) = channel();
    !
    sender1.send(~"ycnerrucnoc hcus");
    sender1.send(~"wow secar ynam");
    sender1.send(~"");
    !
    spawn(proc() {
    loop {
    let code = receiver1.recv();
    sender2.send(code.to_ascii_upper());
    if code == ~"" { break; }
    }
    });
    !
    spawn(proc() {
    loop {
    let code = receiver2.recv();
    if code == ~"" {
    break;
    } else {
    println!("Got back '{:s}'", code);
    }
    }
    });
    }
    Got back 'YCNERRUCNOC HCUS'
    Got back 'WOW SECAR YNAM'
    In this sample we’re communicating directly between to tasks using 2 different channels. We use the first channel to send 2 encrypted messages to the
    first tasks which converts it to upper case and then relays it to a second task to output the results. For this setup you can keep sending messages until a
    blank message is received at which point the listeners quit. I’ve implemented the repeat until using loops and breaks. Most of the code inside the first task
    is just reading and writing to the channel. We could refactor that into another function.

    View full-size slide

  120. fn main() {
    ...
    !
    spawn(proc() {
    loop {
    let code = receiver1.recv();
    sender2.send(code.to_ascii_upper());
    if code == ~""{ break; }
    }
    });
    !
    spawn(proc() {
    loop {
    let code = receiver2.recv();
    let s: ~str = code.chars_rev().collect();
    sender3.send(s);
    if code == ~""{ break; }
    }
    });
    !
    spawn(proc() {
    loop {
    let code = receiver3.recv();
    if code == ~""{
    break;
    } else {
    println!("Got back ‘{:s}’", code);
    }
    }
    });
    !
    ...
    }
    One refactoring later, I’ve got a function called transform for manage the channels. Just tell tell transform which port you’re listening on, which channel
    you’re sending on and a closure for doing the actual transformation. In this case the closure just contains instructions to convert the strings to upper case.
    This will make it really easy to add a 3rd task.

    View full-size slide

  121. fn main() {
    ...
    !
    spawn(proc() {
    loop {
    let code = receiver1.recv();
    sender2.send(code.to_ascii_upper());
    if code == ~""{ break; }
    }
    });
    !
    spawn(proc() {
    loop {
    let code = receiver2.recv();
    let s: ~str = code.chars_rev().collect();
    sender3.send(s);
    if code == ~""{ break; }
    }
    });
    !
    spawn(proc() {
    loop {
    let code = receiver3.recv();
    if code == ~""{
    break;
    } else {
    println!("Got back ‘{:s}’", code);
    }
    }
    });
    !
    ...
    }
    One refactoring later, I’ve got a function called transform for manage the channels. Just tell tell transform which port you’re listening on, which channel
    you’re sending on and a closure for doing the actual transformation. In this case the closure just contains instructions to convert the strings to upper case.
    This will make it really easy to add a 3rd task.

    View full-size slide

  122. fn main() {
    ...
    !
    spawn(proc() {
    loop {
    let code = receiver1.recv();
    sender2.send(code.to_ascii_upper());
    if code == ~""{ break; }
    }
    });
    !
    spawn(proc() {
    loop {
    let code = receiver2.recv();
    let s: ~str = code.chars_rev().collect();
    sender3.send(s);
    if code == ~""{ break; }
    }
    });
    !
    spawn(proc() {
    loop {
    let code = receiver3.recv();
    if code == ~""{
    break;
    } else {
    println!("Got back ‘{:s}’", code);
    }
    }
    });
    !
    ...
    }
    One refactoring later, I’ve got a function called transform for manage the channels. Just tell tell transform which port you’re listening on, which channel
    you’re sending on and a closure for doing the actual transformation. In this case the closure just contains instructions to convert the strings to upper case.
    This will make it really easy to add a 3rd task.

    View full-size slide

  123. fn transform(receiver: Receiver<~str>, sender: Sender<~str>, transformation: |~str| -> ~str) {
    loop {
    let code = receiver.recv();
    if code == ~"" {
    sender.send(~"");
    break;
    }
    sender.send( transformation(code) );
    }
    }
    !
    fn main() {
    ...
    !
    spawn(proc() {
    transform(receiver1, sender2, |x: ~str| x.to_ascii_upper());
    });
    !
    spawn(proc() {
    transform(receiver2, sender3, |x: ~str| x.chars_rev().collect());
    });
    !
    spawn(proc() {
    loop {
    let code = receiver3.recv();
    if code == ~"" {
    break;
    } else {
    println!("Got back '{:s}'", code);
    }
    }
    });
    }
    So now I’m adding a 3rd task and a 3rd channel to reverse the order of the text characters. Giving us…

    View full-size slide

  124. fn transform(receiver: Receiver<~str>, sender: Sender<~str>, transformation: |~str| -> ~str) {
    loop {
    let code = receiver.recv();
    if code == ~"" {
    sender.send(~"");
    break;
    }
    sender.send( transformation(code) );
    }
    }
    !
    fn main() {
    ...
    !
    spawn(proc() {
    transform(receiver1, sender2, |x: ~str| x.to_ascii_upper());
    });
    !
    spawn(proc() {
    transform(receiver2, sender3, |x: ~str| x.chars_rev().collect());
    });
    !
    spawn(proc() {
    loop {
    let code = receiver3.recv();
    if code == ~"" {
    break;
    } else {
    println!("Got back '{:s}'", code);
    }
    }
    });
    }
    So now I’m adding a 3rd task and a 3rd channel to reverse the order of the text characters. Giving us…

    View full-size slide

  125. fn transform(receiver: Receiver<~str>, sender: Sender<~str>, transformation: |~str| -> ~str) {
    loop {
    let code = receiver.recv();
    if code == ~"" {
    sender.send(~"");
    break;
    }
    sender.send( transformation(code) );
    }
    }
    !
    fn main() {
    ...
    !
    spawn(proc() {
    transform(receiver1, sender2, |x: ~str| x.to_ascii_upper());
    });
    !
    spawn(proc() {
    transform(receiver2, sender3, |x: ~str| x.chars_rev().collect());
    });
    !
    spawn(proc() {
    loop {
    let code = receiver3.recv();
    if code == ~"" {
    break;
    } else {
    println!("Got back '{:s}'", code);
    }
    }
    });
    }
    So now I’m adding a 3rd task and a 3rd channel to reverse the order of the text characters. Giving us…

    View full-size slide

  126. use std::ascii::StrAsciiExt;
    !
    fn transform(receiver: Receiver<~str>, sender: Sender<~str>, transformation: |~str| -> ~str) {
    loop {
    let code = receiver.recv();
    if code == ~"" {
    sender.send(~"");
    break;
    }
    sender.send( transformation(code) );
    }
    }
    !
    fn main() {
    let (sender1, receiver1) = channel();
    let (sender2, receiver2) = channel();
    let (sender3, receiver3) = channel();
    !
    sender1.send(~"ycnerrucnoc hcus");
    sender1.send(~"wow secar ynam");
    sender1.send(~"");
    !
    spawn(proc() {
    transform(receiver1, sender2, |x: ~str| x.to_ascii_upper());
    });
    !
    spawn(proc() {
    transform(receiver2, sender3, |x: ~str| x.chars_rev().collect());
    });
    !
    spawn(proc() {
    loop {
    let code = receiver3.recv();
    if code == ~"" {
    break;
    } else {
    println!("Got back '{:s}'", code);
    }
    }
    });
    }
    So now I’m adding a 3rd task and a 3rd channel to reverse the order of the text characters. Giving us…

    View full-size slide

  127. use std::ascii::StrAsciiExt;
    !
    fn transform(receiver: Receiver<~str>, sender: Sender<~str>, transformation: |~str| -> ~str) {
    loop {
    let code = receiver.recv();
    if code == ~"" {
    sender.send(~"");
    break;
    }
    sender.send( transformation(code) );
    }
    }
    !
    fn main() {
    let (sender1, receiver1) = channel();
    let (sender2, receiver2) = channel();
    let (sender3, receiver3) = channel();
    !
    sender1.send(~"ycnerrucnoc hcus");
    sender1.send(~"wow secar ynam");
    sender1.send(~"");
    !
    spawn(proc() {
    transform(receiver1, sender2, |x: ~str| x.to_ascii_upper());
    });
    !
    spawn(proc() {
    transform(receiver2, sender3, |x: ~str| x.chars_rev().collect());
    });
    !
    spawn(proc() {
    loop {
    let code = receiver3.recv();
    if code == ~"" {
    break;
    } else {
    println!("Got back '{:s}'", code);
    }
    }
    });
    }
    Got back 'SUCH CONCURRENCY'
    Got back 'MANY RACES WOW'
    So now I’m adding a 3rd task and a 3rd channel to reverse the order of the text characters. Giving us…

    View full-size slide

  128. youtube: The Rust language: memory, ownership
    and lifetimes - Nicholas Matsakis
    !
    http://rustforrubyists.com
    !
    http://rust-lang.org
    gregmalcolm
    Learning Resources
    speakerdeck: gregmalcolm/rust-me-im-a-developer
    For those of you interested in looking into rust, at the moment, my suggestion for getting started is to look on youtube for a talk by Nicholas Matsakis
    which gives a really nice grounding on Rust. Next off I highly recommend Steve Klabnik’s Rust for Rubyists tutorial, even if you don’t know Ruby. It’s a lot
    easier to follow the current official tutorial. Next off look around the rust website for more.

    View full-size slide