Building a space station in Rust

แชร์
ฝัง
  • เผยแพร่เมื่อ 24 ส.ค. 2022
  • Watch Lost Terminal here: lostterminal.com/
    This video shows you how to build simple Rust programs, starting with your data model.
    If you would like to support what I do, I have set up a patreon here: / noboilerplate Thank you!
    All my videos are built in compile-checked markdown, transcript sourcecode available here github.com/0atman/noboilerplate
    If you would like to support me, you can get special Discord benefits here / noboilerplate
    Corrections are in the pinned ERRATA comment.
    Start your Rust journey here: doc.rust-lang.org/stable/book/
    PROMO
    My name is Tris Oaten and I produce fast, technical videos.
    Follow me here / 0atman
    Website for the show: noboilerplate.org
    Come chat to me on my discord server: / discord
    If you like sci-fi, I also produce a hopepunk podcast narrated by a little AI, videos written in Rust! www.lostterminal.com
    If urban fantasy is more your thing, I also produce a podcast of wonderful modern folktales www.modemprometheus.com
    CREDITS
    Special thanks to my patreon sponsors:
    - Affax
    And to all my patrons!

ความคิดเห็น • 278

  • @NoBoilerplate
    @NoBoilerplate  ปีที่แล้ว +133

    ERRATA
    - 0:43 This is not how format strings look - sorry! It compiles but doesn't do what I wanted.
    - 1:07 misspelled "California"
    - 2:15 duplicate variable name "rand_int", it should of course be "rand_float"
    - Because randomising sections can cause duplicates, your searching will find the FIRST instance of the section, not necessarily the one you want. The fix for this is left as an exercise for the viewer, and future me, apologies!
    - 7:00 thanks to everyone who said that `iter.find()` would be perfect for this job!
    - Thread panic on station breakdown reported by @Mitch557. Logic bug in my game loop, but unrelated to the type system demo github.com/0atman/noboilerplate/issues/9

    • @KyraKrassenburg
      @KyraKrassenburg ปีที่แล้ว +9

      dont forget to pin this comment ;)

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว +16

      @@KyraKrassenburg omgggggg youtube LOVES unpinning it when I edit - THANK YOU!

    • @KyraKrassenburg
      @KyraKrassenburg ปีที่แล้ว +8

      @@NoBoilerplate haha i didnt realise thats what happened.. thats odd lol

    • @xanri7673
      @xanri7673 ปีที่แล้ว +4

      0:42 formatting uses single brackets, you can't put arbitrary expressions inside the brackets, and the method should take &self, not self.

    • @Adrian-ql5yz
      @Adrian-ql5yz ปีที่แล้ว +4

      It was removed from pin once again.

  • @zyansheep
    @zyansheep ปีที่แล้ว +136

    Hey look ma, No Boilerplate uploaded again!

  •  ปีที่แล้ว +147

    From "you can use rust to make your life simpler" to "LETS BUILD A SPACE STATION"
    I like where this is going!

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว +23

      TO THE MOON!

    • @w1keee
      @w1keee ปีที่แล้ว +15

      @@NoBoilerplate come to think of it, rust would be perfect for infrastructure on the moon!

    • @notdumbrella6399
      @notdumbrella6399 9 หลายเดือนก่อน

      @@w1keee And the Mars

  • @tylerbloom4830
    @tylerbloom4830 ปีที่แล้ว +141

    A favorite pattern of mine is the free generic. Say you have several objects with ids that are all the same underlying type, such as Uuid. You can have a type, say TypedId(pub Uuid, PhantomData). This is generic over your structs and only holds PhantomData for the free generic. It is no larger than a Uuid, but now, you can't mistake a Station id for a Section id!!! This is better than `StationId(pub Uuid)` because you only have to implement things once while still getting type safety!!

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว +32

      now that is COOL!

    • @ArrekinWorks
      @ArrekinWorks ปีที่แล้ว +5

      Could you post a small working example?

    • @tylerbloom4830
      @tylerbloom4830 ปีที่แล้ว +18

      ​@@ArrekinWorks ​ ​ Absolutely! In the example, I've also included a link to a project where I'm using this, in case you want a "real world" example.
      Note: TH-cam doesn't like me posting links, so go to the Rust playground and add gist=34f765f98445ca4c2e8da6fbab6a53f8 to the URL​

    • @ArrekinWorks
      @ArrekinWorks ปีที่แล้ว +2

      @@tylerbloom4830 Amazing, Thank you! I'm still early in my days of learning Rust but I already hit this issue with having one type as id for different structs that should not be treated as one type and so far I used structs `Alias(pub IdType)`. I didn't know about PhantomData, so thank you for the larger snippet :)

    • @tylerbloom4830
      @tylerbloom4830 ปีที่แล้ว +1

      @@ArrekinWorks No problem! I was doing the same thing for a while too! What I really wanted was a transparent wrapper. Uuid implements lots of neat stuff, and I'd prefer not to write the boilerplate for it all. But Defer will have to suffice.

  • @w1keee
    @w1keee ปีที่แล้ว +88

    the unrepresantability of invalid states is one of my favourite rust features. i hope the devs add ranged integers soon!

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว +22

      There's already crates that do this, get to it!

    • @Rudxain
      @Rudxain ปีที่แล้ว +1

      Exactly what I was thinking!

    • @r.pizzamonkey7379
      @r.pizzamonkey7379 ปีที่แล้ว +3

      @@NoBoilerplate It does kind of feel like the sort of thing that wouldn't be out of place in std, especially since the compiler could definitely use them as an optimization hint.

  • @clayhudson8892
    @clayhudson8892 ปีที่แล้ว +9

    Im running into an issue where i watch one of your videos to learn about rust and then i wake up 2 hours later because your videos and voice are so peaceful that i drifted off into an afternoon nap. Thanks for making great content.

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว +3

      I'll take that as a complement! If you want actual relaxing content in my voice, I'd love to know what you think of my sifi, hopepunk podcast, Lost Terminal th-cam.com/video/p3bDE9kszMc/w-d-xo.html

    • @erikyoung5139
      @erikyoung5139 9 หลายเดือนก่อน +1

      @@NoBoilerplate I use it for this precise purpose.

    • @NoBoilerplate
      @NoBoilerplate  9 หลายเดือนก่อน

      @@erikyoung5139 thank you!

  • @daskadse769
    @daskadse769 ปีที่แล้ว +33

    7:04 I'd do something like this:
    if let Some(sec) = station.sections.iter_mut().first(|m| m.name == section) {
    sec.active = true;
    }
    If you'd like to panic on not finding it, just else-block panic or use match instead.
    Alternatively, you could just use .for_each(), as Options are iterable themselves. That way you could also easily change from .first() to .filter() if behavior is desired where multiple matches were possible.

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว +9

      Thank you!

    • @Betacak3
      @Betacak3 ปีที่แล้ว +10

      To panic after not finding the section you could also do this:
      let broken_section = station.sections.iter_mut().find(...).expect("Section not found.");
      broken_section.active = true;
      Or alternatively this, if you like doing things in a single statement:
      station.sections.iter_mut().find(...).map(|sec| { sec.active = true; }).expect("Section not found.");
      But I'd personally prefer the first one.

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว +1

      @@Betacak3 Nice, that's much better than indexing!

  • @Singhrager
    @Singhrager ปีที่แล้ว +27

    I don't have a use case that really requires me to use Rust, but hell, you've gone and made it impossible to resist. I just dropped everything I was doing to watch this and was not disappointed. Bravo!

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว +4

      Things you can do in Rust:
      Frontend web dev with yew.rs
      backend web dev with rocket.rs
      game dev with bevy
      Bare-metal coding with many no-std crates!

    • @lardosian
      @lardosian ปีที่แล้ว +3

      @@NoBoilerplate Desktop apps with Tauri, crypto with Solana..

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว +1

      @@lardosian Tauri isn't really Rust, I'd spend my days writing my javascript app INSIDE Tauri, right?

    • @lardosian
      @lardosian ปีที่แล้ว +2

      @@NoBoilerplate Have not actually used Tauri, just heard about it recently.

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว +2

      @@lardosian Yeah, I got quite excited about it as they went 1.0 recently right? However if you look into it, it's an electron clone. A REALLY GOOD ONE, faster and more secure, but you still write your app in web technologies. Not a bad thing, per se, but I'm hardly looking forward to maintaining another js project...!

  • @feathecutie9942
    @feathecutie9942 ปีที่แล้ว +7

    This video just made me so unexplainably happy ^-^ Both because of the amazing technical aspects and the beauty of rust you showcased, but also because of being reminded of Sev through the topic and your voice after having absolutely fallen in LOVE with Lost Terminal the past few days

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว

      I'm so pleased! Thank you! LT is my favourite thing in the WORLD!

  • @seubmarine5347
    @seubmarine5347 ปีที่แล้ว +7

    Wake up babe.
    New No Boilerplate video just dropped.

  • @martinbecker1069
    @martinbecker1069 ปีที่แล้ว +10

    I felt much in the same way as you do when I was building a personal tool.
    I found the `From` trait was extremely helpful in defining how to move from one Type to another, because once I'd done it for all possible types I was using, most of my code was just calling `.into()` and it ended up looking like a flow of data transforming from one state into another.
    A nice side-effect is that almost all of you're logic that handles transforms between Types are easily located in single places (where ever you implemented the `From` trait) so it's all easy to find.

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว +1

      That's a great tip, thank you!

  • @ShreksSpliff
    @ShreksSpliff ปีที่แล้ว +5

    Love your content!
    Turn audio compression down, the unnatural sound is diatracting. Device speakers will compress your voice. Users using earphones won't need the compression.
    Also pushing less air into consonants and more into vowels will do your delivery wonders. You've got a great voice for what you love doing.
    Keep it up and thank you!

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว

      Thanks for the tips Wayne, always appreciated. Could you give me specific timecodes for the problems you're mentioning? Thank you!

    • @BenjaminBrienen
      @BenjaminBrienen ปีที่แล้ว +1

      @@NoBoilerplate I'm not sure what he's referring to. The only thing I noticed was a couple mouth sounds, which is fixed by moving farther from the microphone. Wasn't really a bother, though. Great video! I'm excited to see more specific examples of ways rust has empowered you to write software in a more provable and less guess-and-check way.

    • @dardevelin
      @dardevelin ปีที่แล้ว +2

      @@NoBoilerplate The voice and cadence is literally a + in my opinion.

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว

      @@dardevelin Thank you so much! I just wrapped season 9 of Lost Terminal - I've had a LOT of practice! th-cam.com/video/p3bDE9kszMc/w-d-xo.html

  • @messester7675
    @messester7675 ปีที่แล้ว +3

    This is an amazing guide on how to structure software in general. I have trouble telling my friends and explaining to them how to nicely structure software, and this is an excellent guide. Please make more guides like this because even if only for rust they make for stunning teaching tools.

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว +2

      Well thank you so much! I plan to write a video on Rust modules in a similar way soon!

  • @ottergauze
    @ottergauze ปีที่แล้ว +3

    I just came across this channel and, wow, it has completely revitalised my drive to make stuff in Rust.

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว

      Mission accomplished. The language is incredible, as I try to show in my videos. start here fasterthanli.me/articles/a-half-hour-to-learn-rust then hit the book, and come talk to the community on the discord server (links on noboilerplate.org)

  • @Yotanido
    @Yotanido ปีที่แล้ว +7

    The type state pattern is also incredibly useful here. Things like keeping track of whether a file descriptor is open or closed in the type, or making a builder that requires certain values to be set, is very useful.
    Admittedly, code that makes heavy use of this looks terrible, though. (For the implementation - the API that results from it is very neat :D)

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว +1

      thank you so much for telling me this, I now have a name for the pattern!

    • @darrennew8211
      @darrennew8211 ปีที่แล้ว

      @@NoBoilerplate Tyestate is the part of Hermes that Rust took to make the borrow checker. When the full thing is built directly into the language, it becomes much easier to read everything. Hermes somewhat over-used it, but it would be nice if more languages incorporated it directly.

  • @aidensandbakken6648
    @aidensandbakken6648 ปีที่แล้ว +5

    Note that while Java's type inference isn't as good as Rust's, it can perform type inference based on both sides of the assignment expression. To infer from the left side use the diamond operator:
    ArrayList foo = new ArrayList();
    which is equivalent Rusts's
    let foo: Vec = Vec::::new();
    and to infer from the right side use the var keyword:
    var foo = new Arraylist();
    which is equivalent to Rust's
    let foo = Vec::::new();
    Anyway, nice job on the videos, they're pretty good.

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว +3

      Thank you so much, and thank you for telling me about Java's ability. Using let/var isn't QUITE as nice as Rust though! ;-)

  • @dedenapraia
    @dedenapraia ปีที่แล้ว +2

    Amazing Video !, Thank you very much for giving away this presentation. As a Rust newbie (Coming from high level languages) this kind of explanations are very useful to change the traditional mindset and think in a "Rusty" way. Looking forward for more Videos !. thanks again

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว

      Super! I've also come from high-level languages. I have made a few of these, check out the playlist here and let me know what you think! th-cam.com/video/Q3AhzHq8ogs/w-d-xo.html

  • @rotteegher39
    @rotteegher39 ปีที่แล้ว +2

    I was watching your podcast even before this video came out!

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว

      A Day #1 fan! Thank you so much, I love writing Rust videos, but Lost Terminal is the work I'm most proud of :-)

  • @costelinha1867
    @costelinha1867 ปีที่แล้ว +15

    If he thinks this gives him super powers, wait till he finds out about Bevy's ECS, and how Structs can be used as components.
    (That is assuming he doesn't know it already, or that he's patient enough to sit trough it's compile times, I have a suspicion that he is.)
    (I'm also thinking of trying out macroquad, or the rust bindings for SDL. I was even considering building a ray casting engine in Rust, I mean sure a lot of my code will be from some tutorial, that I'd try to translate to Rust, but it might be fun...)

  • @fallout__boy1130
    @fallout__boy1130 ปีที่แล้ว +1

    Just discover this channel yesterday. This is really nice content, your voice is pleasing to listen to!

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว

      Oh have I got good news for you, there's 9 seasons of me narrating Lost Terminal so far, I'd love to know what you think! th-cam.com/video/p3bDE9kszMc/w-d-xo.html

  • @eignnx_1738
    @eignnx_1738 ปีที่แล้ว +1

    I love the crate suggestions! There are so many great crates out there I didn't even know I wanted

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว

      I've not even SCRATCHED the surface! look at THIS crates.io/crates/no-panic

  • @Medik_0001
    @Medik_0001 ปีที่แล้ว +1

    Love Cool Retro Term. I've also used it for videos myself, love to see it used here also!

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว +1

      Thank you so much! Did you see the podcast videos? th-cam.com/video/p3bDE9kszMc/w-d-xo.html

  • @precumming
    @precumming ปีที่แล้ว +5

    3:06 after functional experience I hate using something before defining. All of my programs you should be able to start on line 1 of the first file and read to the last line of the last file (most languages don't have an order of files but I make a note, so it's easier for me to come back to the project) and you will never come across a reference to something you have not seen the definition of.
    For instance let's say you have never seen the code before and you get to the struct and you see SectionName, you haven't seen that before so you then need to find where the definition is and read it before going backwards back to where you were, and you have to do this for every bit of data that references after the current line which can get annoying having to jump around constantly and it requires more work to understand something.
    I've had someone say to me that they like to have the main thing first because that's what someone reading will see and they will see the context of what some data is before seeing the definition - but to that I say that you have file names to tell you what is contained and then you have sensibly named data so that when it is all combined you should already have a good idea of how it is structured. The tradeoff is that you will be told about things that aren't immediately used that you will need to keep tabs on but that you never jump around.
    Also, my thoughts do start in the main body of the program and then they branch upwards until I reach an end and then I write it. I'm used to F# where the first time I run the program it may already be completely finished.

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว +3

      Rust's the same, if it compiles it works! F# and Rust both take after Haskell in that regard.
      I don't think your 'using something before defining' problems scale well. As soon as you split up your app into multiple files (isn't that most non-trivial programs?) you're going to be jumping to definition anyway? It's a good rule per-file, but imports exist...

    • @Yotanido
      @Yotanido ปีที่แล้ว +9

      Do you need to jump to StationName? It's the name of the station, clearly. If you aren't looking specifically into how names work in the codebase, you probably don't care about the actual implementation. Getting a high-level overview is usually more useful, so I am also of the opinion that the most important bits should come first.
      Define things top-down, if you will.

    • @Gendulf
      @Gendulf ปีที่แล้ว +4

      If you're following the philosophy of making things easier to read because they're going to be read more than written, it makes sense to order things a little differently, namely putting interfaces and public things near the top, and implementation details further down. Sometimes this lines up, but not always.
      It feels "neater" to order things by how to compiler will need it, but humans are good at digging into things only when they need to.

  • @joserobjr7010
    @joserobjr7010 ปีที่แล้ว +6

    Simply amazing!

  • @Ehomer0815
    @Ehomer0815 ปีที่แล้ว +2

    New rust video from tris.. instant like

  • @tentaklaus9382
    @tentaklaus9382 ปีที่แล้ว +5

    Tris you may enjoy a book called "Forever War" by Joel Haldeman. Thanks for inspiring me to keep going deeper with Rust, the struggle never stops ❤️

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว +4

      You're right, it's on my bookshelf right now, loaned to me by a friend and ready to read. I will try to do so.
      I have a recommendation for you: The Spin Trilogy. Incredible stuff.

  • @bmanturner
    @bmanturner ปีที่แล้ว +1

    Instant subscribe. Great video. Informative, interesting and moderately brief

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว

      Thank you so much! Have you seen my other Rust videos, they're all packed with really cool Rust features, and moderately brief too :-D

    • @bmanturner
      @bmanturner ปีที่แล้ว +1

      @@NoBoilerplate I'll be doing a deep dive before long. I smashed the bell for updates.
      Oh, Lost Terminal was really nice. It was clever and humorous and well written, and the music was great. I like how you've paired your passions.

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว

      @@bmanturner Thank you so much! 9 seasons so far!

  • @deer6413
    @deer6413 11 หลายเดือนก่อน +1

    I had a VERY similar idea for a game exactly like the one you talk about! Can't wait to give it a try!

    • @NoBoilerplate
      @NoBoilerplate  11 หลายเดือนก่อน +1

      Try out crates.io/crates/bracket-terminal for your simple game engine!

  • @doormango
    @doormango ปีที่แล้ว +5

    With Rust having so many powerful functional language features like immutability-by-default, first class functions, pattern matching, closures, iterators, and so on, surely it seems the safest Rust paradigm is to have no state at all?

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว

      Love writing code like that, but now and then it's nice to have just a LITTLE state for some problems. I'm glad Rust is pragmatic so I can get work done - the real world is full of state!

    • @doormango
      @doormango ปีที่แล้ว +1

      ​@@NoBoilerplate I guess that is true. I also just learned that Rust does not (I stand to be corrected on this) have good native support for monads, which makes the whole stateless paradigm a lot more frustrating.

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว

      @@doormango I'll have to trust you on that.

  • @gold15o2
    @gold15o2 10 หลายเดือนก่อน +2

    Why do you .expect on section repair when it is easy to assume that section could not be found? Is it really unexpected? Should we panic because of that? I'm asking out of curiosity, is it good approach or should we rather return some kind of error? (Rust newbie here)

    • @NoBoilerplate
      @NoBoilerplate  10 หลายเดือนก่อน +1

      Yes indeed, in a perfect world you don't have any paths that panic at runtime! Check my "rust on rails" video for a better demo of this feature

  • @FelipeBalbi
    @FelipeBalbi ปีที่แล้ว +1

    This was a very entertaining video 🙂 Thoroughly enjoyed

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว

      Thank you so much! There's 12 others in my rust series, I'd love to know what you think about the others!

  • @user-wv1in4pz2w
    @user-wv1in4pz2w ปีที่แล้ว +4

    7:00 I think you could use
    *station.section.iter_mut()
    .find(...)
    .expect(...)
    .active = true;
    or something like that.

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว

      .find()! nice!

    • @Tigregalis
      @Tigregalis ปีที่แล้ว +1

      @@NoBoilerplate Yep, if you look at the documentation e.g. for std:iter::Iterator, or one of the std::collections, you'll find these APIs where you thought you had to do it with two or three methods, or manually handling an index, but there's a method that lets you do it in one with no index required. Much of the time, clippy will pick these up for you too.

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว

      @@Tigregalis no clippy help this time for me, I always run it! thank you!

  • @SEOTADEO
    @SEOTADEO ปีที่แล้ว +1

    Oh my god, this video is great!! I love you, this will save me a lot of trouble. Please make more videos on how to best write Rust Code. And your voice is one of the most charming ones to listen to, reminds me a lot of Sebastian Lague.

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว

      Thank you so much! If you'd like to listen more, you might like my scifi podcast Lost Terminal th-cam.com/video/p3bDE9kszMc/w-d-xo.html

    • @SEOTADEO
      @SEOTADEO ปีที่แล้ว +1

      @@NoBoilerplate Thanks for the hint! I'll listen to everything :)

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว

      @@SEOTADEO Do comment as you go, I'd love to know your thoughts!

  • @pup4301
    @pup4301 ปีที่แล้ว +2

    For enums you could use the discriminant function if you want to know if a enum variant is the right variant you are looking for without describing them. You can also use type_name_of_val function if you want the name of the type but don't know the type name. It is in experimental though.

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว +1

      oh cool, I'll look that up, thank you!

    • @pup4301
      @pup4301 ปีที่แล้ว +1

      Welcome.

  • @creeperkafasi
    @creeperkafasi ปีที่แล้ว +2

    Thanks for another great video!

  • @barisbayrak
    @barisbayrak ปีที่แล้ว +1

    Amazing content. Glad you exist.

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว

      What a nice thing to say! You're very kind, thank you!

  • @the_kovic
    @the_kovic ปีที่แล้ว +1

    While the possibility to use things in a place before you define them certainly feels convenient, as a reader of other people's code, I have learned to appreciate C and its requirement of linearity. I don't have to constantly jump around the code and nothing can ever surprise me because I know that if it's being used, I must have already seen it by the time it is used.

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว +2

      Though I understand where this is coming from, it's only true in trivial programs. Once you start splitting up things into files, you lose this linearity of behaviour.
      However, on the whole, I agree that top-to-bottom reading makes absolute sense - the thing is that sometimes I just want to prototype something close to where I'm working, and then refactor it to the 'correct' position later.

  • @AceofSpades5757
    @AceofSpades5757 ปีที่แล้ว +1

    Fun and informative. Thanks!

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว

      Thank you so much! Did you see my other videos in this Rust series?

    • @AceofSpades5757
      @AceofSpades5757 ปีที่แล้ว +1

      @@NoBoilerplate Yup, looks like almost all of them. I'll probably be checking out the couple I missed this afternoon.

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว

      @@AceofSpades5757 How super, I'd love to hear what you think of them, if you fancy commenting on them.

  • @Rudxain
    @Rudxain ปีที่แล้ว +5

    0:43 I was wondering if Rust supports compile-time range constraints. What if we want Dogs to only have a maximum age of 30? A dog with age 128 is obviously not a Dog.
    What if I want the compiler the throw a compile error when a string doesn't match a constant regex? What if I want the compiler to show me a warning when it can't verify that an arbitrary String matches the regex?
    Raising exceptions when a value is invalid (while its type is correct) is usually done at runtime in most langs. I want to do that at compile-time

    • @PokeNebula
      @PokeNebula ปีที่แล้ว +2

      couldnt this be done manually by writing another line of code with the assert macros?

    • @blucky_yt
      @blucky_yt ปีที่แล้ว +2

      @@PokeNebula Assertion happens at runtime iirc, but you're on the right track, this could probably be implemented with macros

    • @sodiboo
      @sodiboo ปีที่แล้ว +4

      Rust does not support arbitrary constraints about "this type but only these values" in its type system, or at least not directly in the form where the original type is clearly still there. However, const generics are very powerful! And so are macros! There is a crate for your use case with bounded integers, fittingly called bounded_integer. It has a BoundedU32 (and friends matching all of the other integer primitives including BoundedIsize) which takes a minimum and maximum value generically. For example, BoundedU8 if you want dogs to be only between 0 and 30 years old.
      There are some limitations to this approach though, and they don't implement Default among other things. The same crate also has a macro bounded_integer!() which allows you to create a new type which behaves pretty much the same, but macros are slightly more powerful and the type you get out of that will implement some more traits. You could, for example, create the dog age like so: bounded_integer! { pub struct DogAge { 0..=30 } }. I haven't actually used this crate so i don't know why it provides this "struct" form, because the other form of bounded_integer ! { pub enum DogAge { 0..=30 } } should behave the same, but the the enum form makes invalid states unrepresentable by its internal representation, so the compiler can use one of those invalid, out-of-range values to fit other things, so if you might not know the age of a dog, an Option will still be the same size.
      Also note the existence of std::num::NonZeroU8 and friends, which is basically a BoundedU8. The non-zero requirement is the most common range requirement as zero is a funky value for certain operations, and it can't be the denominator in a rational number for example. I think its actual use case and reason for being in stdlib is pointers though, and using similar tricks the compiler knows that a Box can never be null, and represents the None case in an Option as the null pointer. I'm getting carried away though, as this is for some specific optimization reasons and not for the semantic reason you wanted that "well, dogs don't live to hundreds of years", so let's go to the next thing.
      String regexes? Well, there's probably a crate out there for that. Several crates do basically the same thing (though not necessarily based on regexes) such as sqlx with compile-checked queries, and one that i've personally used is hex-literal, which i've used to convert color codes "#FF0000" into an Rgb([u8; 3]) for image processing. And if you've ever written any Rust, i can guarantee you've used println!(). The format string has to match a specific format described in std::fmt module-level documentation.
      The examples i've mentioned for strings all operate on string literals though, but you said "when it can't verify that an arbitrary String matches the regex". Well, no. The compiler doesn't do that. Not for the String type. But what you could do is create a newtype wrapping a String (perhaps even a Cow

    • @Rudxain
      @Rudxain ปีที่แล้ว +1

      @@sodiboo lmao. Don't worry I like learning (and I sometimes also write/talk too much without noticing), I read the whole thing! I already knew about Path strings and OsString, but everything else was very helpful and interesting. Thank you. You should make a video about it, to spread information for other beginners

    • @flyingsquirrel3271
      @flyingsquirrel3271 ปีที่แล้ว +2

      For your dog example the age would have to be known at compile time and not change at runtime. If that's the case, it could be a const generic and in that case there are hacky ways you can use to make compilation fail if it's not in a certain range, not a power of 2, or something like that.

  • @ayoubboudouh7440
    @ayoubboudouh7440 ปีที่แล้ว

    You do great work bro. Keep it up bro.❤❤

  • @devchaudhary78
    @devchaudhary78 ปีที่แล้ว

    Nyc video, something unique thanks man❤️🙂

  • @DavidsKanal
    @DavidsKanal ปีที่แล้ว +3

    2:15 I'm sorry but I fail to imagine how `random` is declared. I get what you're saying about type inference, but Rust doesn't have function overloading, so we can't define both `fn random() -> u8` and `fn random() -> char`, correct? So, how?

    • @pehdfms8621
      @pehdfms8621 ปีที่แล้ว

      random() -> T

    • @Betacak3
      @Betacak3 ปีที่แล้ว +11

      The random() function is a generic function that takes a type parameter that extends a trait. Here's how that works:
      First, you need a trait. Let's call it "Random". It defines a single function that returns the type that implements it:
      trait Random {
      fn random() -> Self;
      }
      Then, you imlement that trait in another type.
      impl Random for SomeType {
      fn random() -> Self {
      // Return a random instance of SomeType
      }
      }
      Now, the random() function itself will look a little something like this:
      fn random() -> T {
      T::random()
      }
      So when you call let foo: SomeType = random(), it will internally call the SomeType::random() function.
      The actual function in the rand crate is actually quite a bit more complicated. But it boils down to this. I hope I managed to explain it well enough.

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว +1

      Thank you for explaining it, that's very clear!

    • @flyingsquirrel3271
      @flyingsquirrel3271 ปีที่แล้ว

      @@Betacak3 Yes! Rust traits are so versatile, they can even be used like "overloading done right".

    • @DavidsKanal
      @DavidsKanal ปีที่แล้ว

      @@Betacak3 I forgot to thank you for this!

  • @plato4ek
    @plato4ek ปีที่แล้ว +2

    Hi! What is that `literate` program used to extract the source code in rust, and where can I find it?

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว +1

      well spotted! It's a crate, just install it with `cargo install literate`!
      I'll update the readme

  • @eboatwright_
    @eboatwright_ ปีที่แล้ว +3

    These would have been SO HELPFUL for me to learn Rust! Also, I like the little text adventure like style here, because I've been writing a text adventure in Rust (with Macroquad for rendering) for over a year now

  • @Elliot.2591
    @Elliot.2591 ปีที่แล้ว +2

    I noticed you have a lot of unwrap calls. Is it safe to use if you are certain what you are unwrapping will not fail?

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว +1

      You're quite right, every unwrap call you make is a chance to improve the reliability of your program.
      However, when you are prototyping, like I am here, you can leave a few in, consider them todos that the compiler understands.
      I use clippy to warn on them, and turn them into errors in my build pipeline!

    • @Elliot.2591
      @Elliot.2591 ปีที่แล้ว

      @@NoBoilerplate I see. Theres a lot to learn here :)

  • @nellykantu8428
    @nellykantu8428 ปีที่แล้ว +1

    You're amazing fr, wish i could code like u

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว +1

      You're too kind: My code is not yet very good, I'm still learning Rust every day! What's your coding experience?

    • @nellykantu8428
      @nellykantu8428 ปีที่แล้ว +2

      @@NoBoilerplate I'm still beginner, was learning Java but dropped it to learn rust

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว

      @@nellykantu8428 Java's not a terrible option especially if you want to get paid!
      Take a look at the graph on this page, any language at the top right you'll be able to get paid work in, in my opinion: redmonk.com/sogrady/2022/03/28/language-rankings-1-22/
      You can learn multiple language at once, too, don't forget! What's your goals, hobby or work?

  • @Wangstalol
    @Wangstalol ปีที่แล้ว +1

    You absolute legend

  • @hussein7859
    @hussein7859 ปีที่แล้ว +1

    this is amazing!

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว +1

      Thank you! I'm not even that good at Rust yet, but the type system has such POTENTIAL! I'll dig deeper in future videos as I figure it out myself!

    • @hussein7859
      @hussein7859 ปีที่แล้ว +1

      @@NoBoilerplate Totally agree that type system has the potential to make the greatest language ever, please keep the great work! I started learning Rust because of your videos and I'm planning to rewrite my side project using it but still not confident enough 😅

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว +1

      @@hussein7859 I'm so pleased! Do come and chat on my discord, ask any questions in #newbie-advice if you need!

    • @hussein7859
      @hussein7859 ปีที่แล้ว +1

      @@NoBoilerplate I will, Thanks!

  • @eaudesolero5631
    @eaudesolero5631 7 หลายเดือนก่อน +1

    Have you given thought to beginning to try to write your own AI/NN/etc using rust?

    • @NoBoilerplate
      @NoBoilerplate  7 หลายเดือนก่อน

      It's not in my area of interest, but there's nearly 1000 ML crates already published! lib.rs/science/ml

  • @ewhac
    @ewhac ปีที่แล้ว +3

    BTW, do you take requests?
    I've started writing some Rust to fiddle with a USB peripheral, and I've made decent progress with the rusb crate. Where things get messy is interpreting the reports sent by the device.
    The structure of the USB device's reports are known, and can be represented by a C struct, which we can reproduce in Rust via the #[repr(C)] directive. In C, you would simply setup a byte buffer, have libusb read the report into it, then (essentially) type-cast the buffer contents to the report structure. But typecasting of this type is a big no-no in Rust, especially if the buffer is mutable.
    There's a facility in the standard library called std::mem::transmute, but it's unsafe, and the autodocs say essentially, "No, seriously, if you think you need this, you probably don't." I took a quick look at serde, but that rabbit hole goes very deep. In short, it looks like all the "obvious" methods for reinterpreting the contents of a memory buffer are unsafe. I was wondering if you knew of a trick that didn't violate Rust's safety rules.

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว +5

      Did you just "Dude, Seriously?" me and then ask for help 20 minutes later?
      Don't worry about it, I forgive you, it's TH-cam making us talk like this, it's all too confrontational here isn't it!
      Come chat to me and the smart folks on the discord - I bet there a few people who could help you out! But be sure to be courteous and recognise that you're asking for help, not demanding it.

    • @ewhac
      @ewhac ปีที่แล้ว +3

      @@NoBoilerplate Your videos are some of the clearest explanations of the advantages and subtleties of Rust I've yet found. It _certainly_ was not my intention to come off as confrontational or entitled, and I apologize.

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว

      @@ewhac Apology absolutely accepted, don't worry about it 🙂

  • @gkttlr1066
    @gkttlr1066 ปีที่แล้ว +1

    How does Rust type system compares to OCaml's?

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว +1

      Extremely similar - the original Rust compiler was written in OCaml!
      I see Rust as Haskell/OCaml dressed in C's clothing (and you can get paid to write it!)

  • @andreitoterman
    @andreitoterman ปีที่แล้ว +2

    7:01 what about
    if let Some(ref mut section) = station.sections.iter_mut().find(|m| m.name == section) {
    section.active = true;
    }

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว

      Nice, yeah great optimisation!

  • @SriKadimisetty
    @SriKadimisetty ปีที่แล้ว +2

    Nice work, beginning to look forward to these now :) Small feedback though - could you look into putting a pop filter or something similar over your mic, the `s` sounds currently are too harsh on the ears.

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว +3

      interesting, I'll look into it.
      (A pop shield won't do anything for sibilants, that's for plosives, but your feedback stands, thank you)

    • @SriKadimisetty
      @SriKadimisetty ปีที่แล้ว +1

      @@NoBoilerplate Gotcha. I learn something new everyday :)

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว +3

      @@SriKadimisetty I've got a lifetime of music production under my belt, and 2 years of intensive podcasting for Lost Terminal, so I'm always optimising my audio pipeline!
      btw have you heard it? th-cam.com/video/p3bDE9kszMc/w-d-xo.html

  • @CT-cx8yi
    @CT-cx8yi ปีที่แล้ว +1

    What do you use to create your slideshows?

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว +1

      Obsidian.md. I talked about it in the middle of this video, it's GREAT! th-cam.com/video/ifaLk5v3W90/w-d-xo.html

    • @CT-cx8yi
      @CT-cx8yi ปีที่แล้ว +1

      Thanks! Great videos.

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว

      @@CT-cx8yi Thank you so much!

  • @dream_emulator
    @dream_emulator ปีที่แล้ว

    Awesome possum ⚡️

  • @RoamingAdhocrat
    @RoamingAdhocrat ปีที่แล้ว +1

    2:30 can you not create a shuffed vector in one step, by chaining `shuffle` off `collect`?

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว

      Yeah! Well spotted, I love chaining method calls like this!

    • @RoamingAdhocrat
      @RoamingAdhocrat ปีที่แล้ว +1

      @@NoBoilerplate Then it wouldn't need to be mutable, right? I thought perhaps you'd done it on two lines for readability

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว

      @@RoamingAdhocrat I do try to keep things as readable as I can, and my code is far from perfect! My goal with this video was to talk about structs and enums and emphasise that modelling your correct states is vital when building a Rust app.
      There are lots of improvements to the code that need doing!

  • @dominikkormann1840
    @dominikkormann1840 ปีที่แล้ว +1

    in the beginning when implementing the Name enum
     5 #[derive(Debug, RandGen, Display)] ■■ this function takes 2 arguments but 1 argument was supplied supplied 1 argument
    ▎ 4 enum Name {
    ▎ 3 Akira, Californa, Daedalus,
    ▎ 2 Eisenberg, Interpid, Miranda,
    ▎ 1 Nova, Reliant, Sagan
    ▎ 24 }
    I get the Error that RandGen takes 2 arguments but 1 is supplied and I cannot get rid of it
    can someone help?

    • @dominikkormann1840
      @dominikkormann1840 ปีที่แล้ว +1

      edit: solved. I used the wrong version of rand 0.7 instead of 0.8

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว

      Super! This is somewhat my fault as I don't check in my cargo.toml. I will fix this for the next video!

  • @teeesen
    @teeesen ปีที่แล้ว +1

    Nice video. But here’s what I’m missing: What are the states in the example that are invalid and why are they unrepresentable?

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว +1

      Ah, it's not the greatest example was it? I have a lot to learn about Rust and I will build better examples as I learn too.
      HOWEVER the answer here is that the naming examples I used. Strings can have any names, using Enums allows compiler-validated options.

    • @teeesen
      @teeesen ปีที่แล้ว +2

      Thanks. That’s what I was wondering. It’s a fine example as far as it goes. I can see that Rust enums are an improvement over C enums, but that’s not a high bar. As programmers what we do want to be able to build types that allow objects to reach only valid states. I think the video articulates that goal well. The way to achieve this is some combination of compile time checking and encapsulation. Encapsulation means that the code that needs to be checked to ensure that only valid states can be reached is limited. Obviously strong static type checking helps here. Mutability restrictions also help. In Java, if a field is “final”, I only have to check the code in the constructors to check that its value is legitimate; and if a field is private, I only need to check the code of one class. If a language distinguishes between mutators and accessors, then I don’t need to check the accessors to see that invariants are respected. I don’t know Rust, but maybe it has something to add here. Another thing that helps is if the language gives a way to express invariants in the language itself; Euclid, Turing, and Eiffel all had this combined with runtime checking. Languages like Dafny, with compile-time verification, and languages like Agda, with dependent types (as another commenter mentioned), give you ways to express nontrivial invariants that can be checked at compile time. In a way, this restricts that amount of code that needs to be checked by the developer down to the code that expresses the invariant. It will be interesting to know more about how Rust supports this goal.

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว

      @@teeesen Absolutely, this is a really good idea for a future video - thank you!

  • @sharperguy
    @sharperguy ปีที่แล้ว +1

    "Make invalid states unrepresentable" "Don't you see that the whole aim of Newspeak is to narrow the range of thought? In the end we shall make thought-crime literally impossible, because there will be no words in which to express it."

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว

      You've got the principle exactly, nice analogy! I might steal that (with attribution) for a video...! :-D

    • @sharperguy
      @sharperguy ปีที่แล้ว +1

      @@NoBoilerplate you should credit George Orwell

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว +1

      @@sharperguy oh yes of course, but I mean the link between limiting invalid states and newspeak - that's great! 🙂

  • @kira.herself
    @kira.herself ปีที่แล้ว +1

    Lovely Name enum :D

  • @weirdo911aw
    @weirdo911aw ปีที่แล้ว +4

    Mr. Plate,
    Could you make a video on WebAssembly (please 🥺🥺🥺)?
    kthanksbye

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว +2

      I may do in the future, but for now just use yew.rs it's great!
      And PLEASE! Mr Plate is my father, call me Nob Oiler.

    • @Speykious
      @Speykious ปีที่แล้ว +1

      "Mr. Plate"
      lmao

  • @quettle
    @quettle ปีที่แล้ว +1

    for 7:06, station.sections.iter_mut().find(|m| m.name= = section).expect("...").active = true should work

  • @vanvothe4817
    @vanvothe4817 ปีที่แล้ว +1

    I like it

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว

      I love it! horse.gif
      Have you seen my other videos? don't watch my last one, I made big mistakes about Go lol!

  • @BranceBoren
    @BranceBoren ปีที่แล้ว +1

    Anyone else read the Rust book in Tris's voice now?

  • @Dygear
    @Dygear ปีที่แล้ว +1

    Huh, I didn't know that format!("{{self.name}}{{self.age}}") was valid syntax. I gotta go rewrite some of my code.

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว +1

      It's not - sorry! Typo there. It COMPILES but is not valid!

    • @Dygear
      @Dygear ปีที่แล้ว +1

      @@NoBoilerplate ha! I was trying to figure out why when I tired it, it didn’t work. This seems like a sensible addition as it does take variable names directly now, why not also structs?

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว

      @@Dygear I had a nightmare I wars writing python and it came true 😂

  • @notusingmyrealnamegoogle6232
    @notusingmyrealnamegoogle6232 ปีที่แล้ว +3

    While I think we all appreciate the hustle of trying to get more views for your projects the length of the pitch for the podcasts is beginning to distract from the content of these videos which are where you are excelling and finding an audience.

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว +4

      I understand, it won't be an often repeated thing. However your options are for me to tell you about my own projects for 30s or to advertise NordVPN for 30s. I am not very interested in nordvpn.

    • @Yotanido
      @Yotanido ปีที่แล้ว +2

      @@NoBoilerplate Honestly, I think it was fine. I sponsor block, but have it set to not automatically skip self-promotions. It gave me the option, but I decided not to skip it.
      It's not like some other videos where they have 3 minute sponsor segments in their 5 minute videos... Plus, it was at least tangentially relevant to the video, so it wasn't as jarring as these things usually are.

    • @notusingmyrealnamegoogle6232
      @notusingmyrealnamegoogle6232 ปีที่แล้ว +1

      @@NoBoilerplate yeah that’s fair, the deeper integration into the video in this case threw me off because it wasn’t clear how much of the topic was guided by what you think is most useful to know and what was relevant to podcasts

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว +1

      @@notusingmyrealnamegoogle6232 Thank you for your understanding. I will very likely do a few external sponsors now and then, but not freakin' squarespace, I'd rather they be Rust specific companies or tech or something relevant to my audience.
      The bottom line is that if I can make some money from these videos I can do fewer hours at my day job and make more and better videos for the channel!

  • @MithicSpirit
    @MithicSpirit ปีที่แล้ว +1

    0:36 why would anyone want to program like in OOP? Also Rust does have typeclasses, they're just called traits instead ;)

  • @kungfooman
    @kungfooman ปีที่แล้ว +1

    Does it even support Multiple Dispatch? Everytime I look at Rust, it just looks ugly. Why not something nice like TypeScript, with Rust compiler?

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว

      Can you explain why I would need multiple dispatch? I've not used a language that has it.

  • @sammcalonan847
    @sammcalonan847 ปีที่แล้ว +2

    What if we played Among Us on the No Boilerplate space station? 😳

  • @tudbut
    @tudbut ปีที่แล้ว +3

    Rust

  • @hh-dr4db
    @hh-dr4db ปีที่แล้ว +1

    What is that noise?

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว

      You'll have to be more specific!

  • @PokeNebula
    @PokeNebula ปีที่แล้ว +1

    i enjoy your other videos, as theyre what motivated me to learn rust to supplement my own diet of python spaghetti, but after a point the insights of a long-time developer would do nothing but go over the head of a beginner like me. Thats why this video made me so excited, before i wasted a lot of time over this confusion:
    at 1:12 you introduce the rand_derive 2 crate and the randgen trait, but not Display. Is this a mistake? i had to go looking through the docs.rs to find the displaydoc crate, and i still couldnt be sure it was the right crate with a Display trait, since you don't show the use statement that would clarify. even then, the text you show on screen wouldnt compile: the Display trait asks you to write doc comments for every member of the enum...... which is redundant, because the enum's members are names, and names are self-explanatory.
    You never mention the Display trait by name in the video, and using the displaydoc crate, the code on screen woud not compile, and if it did, then the trait would seemingly help nothing. Is its inclusion in error?

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว

      Take a look at the source markdown, on my linked repo, some code I have no time to show in the videos, but the compiler sees it! I should have included a note about Display, however. Thank you!

  • @localboxcrox
    @localboxcrox ปีที่แล้ว +1

    🦀

  • @AshtonSnapp
    @AshtonSnapp ปีที่แล้ว +1

    And of course, I’m going to take this and blow the scope like a hot air balloon.

  • @RoamingAdhocrat
    @RoamingAdhocrat ปีที่แล้ว +1

    can't put boilers into space.
    they're too heavy

  • @SeniorSpaceflight
    @SeniorSpaceflight ปีที่แล้ว +1

    am
    am i the only one who thought he was gonna make a space station in Rust
    THE SURVIVAL GAME RUST?

  • @ewhac
    @ewhac ปีที่แล้ว +2

    0:30: "But how do we design programs in Rust? There's no classes!"
    Dude, seriously? Some of your audience are veteran users of C and assembly code, and they don't have classes, either.
    6:00: _(sigh...)_ I've never understood this pattern -- two different functions that, save for one tiny difference, perform _identical_ operations. This way leads to code bloat. You should parameterize the boolean test, along the lines of (horrible formatting ahead):
    fn sections_with_active (&self, active: bool) -> Vec { self.sections.iter().filter (|m| m.active == active).map (|m| m.name.to_string()).collect() }
    Which you can then call as `station.sections_with_active (true)` or `station.sections_with_active (false)`, which is hopefully sufficiently mnemonic.

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว +1

      noted.

    • @31redorange08
      @31redorange08 ปีที่แล้ว +1

      Boolean parameters considered harmful.

    • @Jakob7539511
      @Jakob7539511 ปีที่แล้ว +1

      @@31redorange08 That's mainly for flags, that change the control flow of the whole method. This use looks very nice :)

    • @Yotanido
      @Yotanido ปีที่แล้ว +3

      I don't really like that as a public API. It doesn't read as nice.
      You could absolutely have working_sections and broken_sections call this new sections_with_active, though - I do prefer that.

  • @ameypendokhare3832
    @ameypendokhare3832 ปีที่แล้ว +2

    NASA should use rust as their official programming language... (after watching this I hope so)
    its always better to evolve with time
    RUST is evolution...
    >Rust for next 40 years {spread the word}

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว +2

      Rust's not yet PROVEN (mathematically) for safety critical systems, when people's lives are on the line, you gotta be SURE.
      It may be, but it's not there yet.
      Doesn't matter for 99.99% of applications, of course. (how else do you explain php?!)

    • @lucky-segfault4219
      @lucky-segfault4219 ปีที่แล้ว +1

      @@NoBoilerplate are there any languages that are proven mathematically? surely C can't be with all the many many many ways there are to trigger undefined behavior

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว

      @@lucky-segfault4219 The ones used in autopilots and pacemakers are, en.wikipedia.org/wiki/Ada_(programming_language) and co.
      They either use or have core features proven by Formal Methods such as Z, B, Coq and so on.
      It's not really a deficiency in Rust, as to formally prove programs, their state has to be SO TINY (think pacemaker inputs and outputs) and a single unbounded string can make your function impossible to prove.

    • @lucky-segfault4219
      @lucky-segfault4219 ปีที่แล้ว +1

      @@NoBoilerplate oh neat. Well, it sounds like rusts ability to create programs that can't represent invalid states might be a useful base for proving individual programs are mathematically provable, even if the language itself still has openings for errors

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว

      @@lucky-segfault4219 Certainly. Just like seatbelts, a policy doesn't have to stop every fatality for it to be wildly successful. Rust feels like 99% of my day-to-day errors in python just can't happen. Wonderful!

  • @Mankepanke
    @Mankepanke ปีที่แล้ว

    F in the chat for all the dogs killed by people reading their name tags.
    Dead, but not forgotten 🕊️🕊️🕊️

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว

      I don't understand?

    • @Mankepanke
      @Mankepanke ปีที่แล้ว +1

      @@NoBoilerplate The name tag method used "self" and not "&self", so the method took ownership of the dog and freed it.
      Try it yourself, you cannot access the dog instance after calling the name tag method.
      It's just a joke, though. :)

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว +1

      @@Mankepanke oh so it did! Ha!

  • @ironnoriboi
    @ironnoriboi ปีที่แล้ว

    To think that I'd need Sponsorblocker for your videos. Bleh

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว

      I don't mind at all, I totally understand. However, I'm hoping to do these videos professionally, and the way to do that is through advertising. If I can get sponsorship from relevant companies (not squarespace lol) then I'll be able to dedicate more time to making these videos for you. That sounds like a win/win for everyone!

    • @ironnoriboi
      @ironnoriboi ปีที่แล้ว +1

      @@NoBoilerplate I'm of the opinion that people TH-cam-ing fulltime ruined the feeling of the platform. It is very corporate and business now. It is hard to find users that make videos in their free time for fun, which was very easy years ago when TH-cam was still a smaller platform where nearly nobody did it full time.

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว

      @@ironnoriboi I don't think this is the right way to look at it. Let me know your thoughts on this, which says it much better than I could: th-cam.com/video/sUsI6W7-d28/w-d-xo.html

  • @lucky-segfault4219
    @lucky-segfault4219 ปีที่แล้ว +3

    7:01 I'd use the filter Function. For example, you can remove all elements of a list that are 3 like this:
    let v = vec![ 1, 3, 2, 11, u16::MAX ];
    let v = v.into_iter()
    .filter( | item | item != 3 )
    .collect();
    Great video, and I'll be sure to have a look at that podcast

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว +1

      nice thank you! I do hope you like the podcast, it's something I'm so proud of!

  • @oconnor663
    @oconnor663 ปีที่แล้ว +1

    > I'm not delighted by having to resort to indexing the vector.
    I would lean towards using a regular for-loop for this, maybe something like:
    for section in &mut station.sections {
    if section.name == section_name {
    section.active = true;
    // break?
    }
    }
    You could also consider making your sections a HashMap instead of a Vec, with the section name enum as the key to the map. That would let you get rid of the loop here, and it would let you guarantee that you never have multiple sections with the same name. If you wanted to get really crazy, you could even assign values starting with 0 to your SectionName enum, and you could use an array of (optional?) Sections indexed by the value of their SectionName. Ideally you could set the size of the array to the number of enum variants without any duplication, but I'm not sure there's a good way to do that today. Something more verbose like this example using a struct could also work: doc.rust-lang.org/std/ops/trait.Index.html#examples

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว

      Nice! I've also had suggestions of using inter.find().

  • @sodiboo
    @sodiboo ปีที่แล้ว +2

    7:00 how about this?
    station.sections
    .iter_mut()
    .find(|m| m.name)
    .expect("Section not found.")
    .active = true;

  • @urbanelemental3308
    @urbanelemental3308 ปีที่แล้ว +1

    @NoBoilerplate, here's what ChatGPT helped me make. Is there no crate already out there that does this?
    use std::io::{stdout, stdin, Write};
    use std::str::FromStr;
    pub fn prompt(message: &str, validate: F) -> T
    where T: FromStr,
    T::Err: std::fmt::Debug,
    F: Fn(&str) -> Result
    {
    loop {
    print!("{}", message);
    stdout().flush()
    .expect("Failed to flush stdout");
    let mut input = String::new();
    stdin().read_line(&mut input)
    .expect("Failed to read input");
    let input = input.trim();
    match validate(input) {
    Ok(value) => return value,
    Err(error) => println!("{}", error),
    }
    }
    }
    pub fn prompt_value(message: &str) -> T
    where T: FromStr,
    T::Err: std::fmt::Debug
    {
    prompt(message, |input| {
    match input.parse() {
    Ok(value) => Ok(value),
    Err(_) => Err("Error parsing input"),
    }
    })
    }

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว

      ChatGPT's fun isn't it! I also am using as part of my daily work.
      HOWEVER this seems wildly complex. Do you really need all that generic stuff? I see you're more interested in the input side than the validate side (your code expects a validate function to be passed in)
      There's lots of input crates available crates.io/search?q=input
      What are you attempting to do?

    • @urbanelemental3308
      @urbanelemental3308 ปีที่แล้ว +1

      @@NoBoilerplate With the FromStr (trait?) it allows for identifying a parsable type. That way you can simply do this:
      mod prompt;
      use prompt::prompt_value;
      fn main() {
      let age = prompt_value::("Enter your age: ");
      println!("Your age is: {}", age);
      }
      It's nice because prompt_value won't return until it has a valid value. Command line apps are my way of experimenting.

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว

      @@urbanelemental3308 that's so cool! Turbofish is a DELIGHT

    • @urbanelemental3308
      @urbanelemental3308 ปีที่แล้ว +1

      @@NoBoilerplate Ah yes. I love that iterables are seemly built in.

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว

      @@urbanelemental3308 oh I LOVE iters. Have you seen: crates.io/crates/rayon

  • @real1cytv
    @real1cytv ปีที่แล้ว +1

    7:05 what about the Iterator::find method? You can just use a |m| m.name == section as the predicate...

  • @YTCrazytieguy
    @YTCrazytieguy ปีที่แล้ว +1

    I think you want:
    station.sections.iter_mut().find(|m| m.name == section).expect("Section not found.").active = true;

  • @robinmoussu
    @robinmoussu ปีที่แล้ว +1

    You have an interesting channel. I just discovered it thanks to @codetothemoon

    • @NoBoilerplate
      @NoBoilerplate  ปีที่แล้ว

      Thank you so much! My latest video has a shout-out to CTTM :-)

  • @heraclitoqsaldanha6133
    @heraclitoqsaldanha6133 ปีที่แล้ว +1

    🦀