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

Lessons from Rust (2019-11-22)

Lessons from Rust (2019-11-22)

Pijus Navickas

November 22, 2019
Tweet

More Decks by Pijus Navickas

Other Decks in Programming

Transcript

  1. fn main() { let a = vec!(1, 2, 3, 4);

    // ... } // a gets deallocated.
  2. fn sum(values: Vec<i32>) -> i32 { // ... } //

    a gets deallocated. fn main() { let a = vec!(1, 2, 3, 4); let sum_of_a = sum( a); // a is no longer accessible here. // ... } https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=192e9a1c3c68c4f0727c940af1922ba0
  3. fn sum(values: Vec<i32>) -> i32 { // ... } fn

    main() { let a = vec!(1, 2, 3, 4); let sum_of_a = sum(a); // ... } It’s also called “moving”... size: 4 values: ... size: 4 values: null size: 4 values: ...
  4. fn sum(values: &Vec<i32>) -> i32 { // ... } fn

    main() { let a = vec!(1, 2, 3, 4); let sum_of_a = sum( &a); // ... } // a gets deallocated. https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=310a6888d7f682d3c0535f97a3f5ea99
  5. fn sum(values: &mut Vec<i32>) -> i32 { // ... }

    fn main() { let mut a = vec!(1, 2, 3, 4); let sum_of_a = sum( &a); // ... } // a gets deallocated.
  6. let x = 0; // Immutable. let mut x =

    0; // Mutable fn do_something( &self) { } // Immutable. fn do_something( &mut self) { } // Mutable. fn do_something(value: &i32) { } // Immutable. fn do_something(value: &mut i32) { } // Mutable.
  7. fn do_something(value: &i32) { } fn do_something(value: &mut i32) {

    } fn do_something( mut value: &i32) { } fn do_something( mut value: &mut i32) { } They all are different...
  8. error[E0502]: cannot borrow `a` as mutable because it is also

    borrowed as immutable Or else... error[E0499]: cannot borrow `a` as mutable more than once at a time
  9. struct Container< T> { value: T, } fn do_something< T>(value:

    T) { // ... } trait Calculator< T> { fn compute(a: T, b: T) -> T; } enum Node<T> { VALUE(T), EMPTY, }
  10. Just have in mind... struct Container< T> { value: T,

    } struct Container< i32> { value: i32, } struct Container< String> { value: String, } Becomes (for real-real)... Same for functions and enums.
  11. trait HasPriority { fn priority(&self) -> i32; } struct ExpensiveAd

    { } impl HasPriority for ExpensiveAd { fn priority(&self) -> i32 { 9000 } } struct UserContent { } impl HasPriority for UserContent { fn priority(&self) -> i32 { 2 } }
  12. trait Face { fn is_nice(&self) -> bool; } struct Fez

    { } struct Fedora { } struct YourFace<Hat> { hat: Hat, }
  13. impl Face for YourFace<Fedora> { fn is_nice(&self) -> bool {

    false } } impl Face for YourFace<Fez> { fn is_nice(&self) -> bool { true } }
  14. fn main() { let with_fedora = YourFace { hat: Fedora

    { }, }; let with_fez = YourFace { hat: Fez { }, }; println!("You look nice? {}", with_fedora.is_nice()); // false println!("You look nice? {}", with_fez.is_nice()); // true } https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=0f60ca55068c829a3a639865c56bb75a
  15. pub trait Clone { fn clone(&self) -> Self; fn clone_from(&mut

    self, source: &Self) { ... } } From standard SDK... fn main() { ... with_fedora.clone(); with_fez.clone(); }
  16. Attempt v1.0 ... impl<T> Clone for YourFace<T> { fn clone(&self)

    -> Self { YourFace { hat: self.hat, } } } | 14 | hat: self.hat, | ^^^^^^^^ move occurs because `self.hat` has type `T`, which does not implement the `Copy` trait
  17. Attempt v2.0 ... impl<T: Clone> Clone for YourFace<T> { fn

    clone(&self) -> Self { YourFace { hat: self.hat.clone(), } } } https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=8c8d29248bf70b06a5b1a960cbc10dfa
  18. trait Name { fn name(&self) -> String; } trait Greeting

    { fn hello(&self); } https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=6304dd6acd15a070a558ecc7c8aa0482 impl<T> Name for YourFace<T> { fn name(&self) -> String { String::from("Pit") } } impl<T: Name> Greeting for T { fn hello(&self) { println!("Hello, {}!", self.name()) } }
  19. fn main() { let face = YourFace { hat: Fedora

    { }, }; face.hello(); } https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=9ebd1f6027a3202052cb4dc350e98167
  20. struct Container< i32> { value: i32, } struct Container< String>

    { value: String, } 4 B 24 B enum Action { Kiss(i32, i32, i32, i32), Hug(i32, i32), Ignore, } 20 B trait Name { fn name(&self) -> String; } --- B
  21. EVERYTHING HAS TO BE SIZED! --> src/main.rs:5:25 | 5 |

    fn do_something(person: Name) { | ^^^^ help: use `dyn`: `dyn Name` | = note: `#[warn(bare_trait_objects)]` on by default error[E0277]: the size for values of type `(dyn Name + 'static)` cannot be known at compilation time trait Name { fn name(&self) -> String; }
  22. Zero cost abstractions What you don’t use, you don’t pay

    for. What you do use, you couldn’t hand code any better. Bjarne Stroustrup, creator of C++
  23. Internal iterators ... fn main() { let names = vec!("John",

    "Steve"); names.iter() .for_each(|v| println!("Hello, {}.", v)); } https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=d4948f4ae81ca20cba42da18bd9f6ed7
  24. - Pull (rather than push): - Same as NIO. -

    Small footprint (no scheduling). - Compiles to a state machine. - Small footprint (allocates memory only once). - Lazy (sort of). pub trait Future { type Output; fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output>; } Implicit contract: once polled, will notify executor when value is ready.
  25. async fn first_function() -> u32 { .. } async fn

    another_function() { // Create the future: let future = first_function(); // Await the future, which will execute it (and suspend // this function if we encounter a need to wait for I/O): let result: u32 = future .await; ... }
  26. Change syntax. Do compile-time checks. Generate meaningful error messages. Generate

    code (aka boilerplate). Be applied to anything. Look like a function call.