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. Lessons From Rust Rust for those who’s not gonna do

    Rust Pijus Navickas
  2. Disclaimer! This is not a RUST tutorial!* *It may look

    like a RUST tutorial.
  3. Ownership & Borrowing

  4. None
  5. Memory Management: Ownership

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

    // ... } // a gets deallocated.
  7. EASY!

  8. Memory Management: Transferring Ownership

  9. 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
  10. 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: ...
  11. Memory Management: Borrowing

  12. 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
  13. 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.
  14. Memory Management: Mutability

  15. 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.
  16. EASY!

  17. MEH!

  18. 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...
  19. EASY!

  20. MEH!

  21. You know Rust memory management

  22. So, what’s the fuss all about?

  23. Because compiler

  24. Mutable Shared Mutable Shared Pick one

  25. 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
  26. Think of... - Caches. - Parallel processing. - Lambdas.

  27. None
  28. Takeaway 001 Ownership and borrowing helps avoiding data races

  29. Takeaway 001.2 Rust memory management is safer but more complicated.

  30. Fun fact! Rust used to have GC

  31. Type system

  32. Type System: Generics

  33. 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, }
  34. 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.
  35. EASY!

  36. MEH!

  37. Type System: Traits

  38. 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 } }
  39. EASY!

  40. Am...

  41. trait Face { fn is_nice(&self) -> bool; } struct Fez

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

    false } } impl Face for YourFace<Fez> { fn is_nice(&self) -> bool { true } }
  43. 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
  44. 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(); }
  45. 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
  46. 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
  47. EASY?

  48. Not all vectors are made equal

  49. Note: there is no method overloading! https://doc.rust-lang.org/std/vec/struct.Vec.html

  50. Implementing trait for traits

  51. 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()) } }
  52. fn main() { let face = YourFace { hat: Fedora

    { }, }; face.hello(); } https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=9ebd1f6027a3202052cb4dc350e98167
  53. developing in Rust

  54. Question is... How do you DISCOVER what implements what? READ

  55. #emojiface

  56. Benefit? Conditional implementation More specialised implementations { Compile time!

  57. Lesson learned: Rust is hard

  58. Lesson learned: Rust is hard That’s not the point!

  59. Takeaway 002 Inheritance is not the only way to do

    polymorphism.
  60. Takeaway 002.2 Rust type system is more powerful but more

    complicated.
  61. Fun fact! Rust used to have classes

  62. But it’s fun fun fun!

  63. Sometimes but it’s .

  64. Also, there is more!

  65. Type System: Sized Types

  66. 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
  67. Why does it matter?

  68. 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; }
  69. Takeaway 003 Rust REALLY cares about memory management.

  70. 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++
  71. Compiler, of course.

  72. It does a lot.

  73. But not tail recursion. Yet.

  74. We already talked about... Generating structs and methods tailored for

    the types used.
  75. 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
  76. Takeaway 004 High level code doesn’t have to be slow.

  77. Futures

  78. - 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.
  79. 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; ... }
  80. Takeaway 005 You can have async with little noise.

  81. MACROS I love macros! No developer of C++

  82. Rust loves macros!

  83. Macros can do anything!

  84. Change syntax. Do compile-time checks. Generate meaningful error messages. Generate

    code (aka boilerplate). Be applied to anything. Look like a function call.
  85. Takeaway 006 Macros can be sanity-friendly.

  86. Thank You Pijus Navickas