Building a space station in Rust

Поделиться
HTML-код
  • Опубликовано: 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  Год назад +134

    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 Год назад +139

    Hey look ma, No Boilerplate uploaded again!

  • @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: RUclips 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.

  •  Год назад +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  Год назад +24

      TO THE MOON!

    • @w1keee
      @w1keee Год назад +15

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

    • @notdumbrella6399
      @notdumbrella6399 10 месяцев назад

      @@w1keee And the Mars

  • @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 ruclips.net/video/p3bDE9kszMc/видео.html

    • @erikyoung5139
      @erikyoung5139 11 месяцев назад +1

      @@NoBoilerplate I use it for this precise purpose.

    • @NoBoilerplate
      @NoBoilerplate  11 месяцев назад

      @@erikyoung5139 thank you!

  • @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.

  • @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...!

  • @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!

  • @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.

  • @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!

  • @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)

  • @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 :-)

  • @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! ruclips.net/video/p3bDE9kszMc/видео.html

  • @joserobjr7010
    @joserobjr7010 Год назад +6

    Simply amazing!

  • @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! ruclips.net/video/Q3AhzHq8ogs/видео.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? ruclips.net/video/p3bDE9kszMc/видео.html

  • @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.

  • @seubmarine5347
    @seubmarine5347 Год назад +7

    Wake up babe.
    New No Boilerplate video just dropped.

  • @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! ruclips.net/video/p3bDE9kszMc/видео.html

  • @barisbayrak
    @barisbayrak Год назад +1

    Amazing content. Glad you exist.

    • @NoBoilerplate
      @NoBoilerplate  Год назад

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

  • @Ehomer0815
    @Ehomer0815 Год назад +2

    New rust video from tris.. instant like

  • @creeperkafasi
    @creeperkafasi Год назад +2

    Thanks for another great video!

  • @deer6413
    @deer6413 Год назад +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  Год назад +1

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

  • @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!

  • @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!

  • @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.

  • @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! ;-)

  • @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.

  • @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...)

  • @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.

  • @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.

  • @devchaudhary78
    @devchaudhary78 Год назад

    Nyc video, something unique thanks man❤️🙂

  • @ayoubboudouh7440
    @ayoubboudouh7440 Год назад

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

  • @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.

  • @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 ruclips.net/video/p3bDE9kszMc/видео.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!

  • @Wangstalol
    @Wangstalol Год назад +1

    You absolute legend

  • @dream_emulator
    @dream_emulator Год назад

    Awesome possum ⚡️

  • @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?

  • @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.

  • @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!

  • @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

  • @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!

  • @gold15o2
    @gold15o2 Год назад +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  11 месяцев назад +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

  • @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!

  • @kira.herself
    @kira.herself Год назад +1

    Lovely Name enum :D

  • @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.

  • @BranceBoren
    @BranceBoren Год назад +1

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

  • @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? ruclips.net/video/p3bDE9kszMc/видео.html

  • @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!

  • @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 RUclips 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 🙂

  • @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 :)

  • @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

  • @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!

  • @tudbut
    @tudbut Год назад +3

    Rust

  • @eaudesolero5631
    @eaudesolero5631 8 месяцев назад +1

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

    • @NoBoilerplate
      @NoBoilerplate  8 месяцев назад

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

  • @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! 🙂

  • @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!)

  • @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!

  • @quettle
    @quettle Год назад +1

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

  • @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! ruclips.net/video/ifaLk5v3W90/видео.html

    • @CT-cx8yi
      @CT-cx8yi Год назад +1

      Thanks! Great videos.

    • @NoBoilerplate
      @NoBoilerplate  Год назад

      @@CT-cx8yi Thank you so much!

  • @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 😂

  • @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;
    }

  • @sammcalonan847
    @sammcalonan847 Год назад +2

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

  • @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

  • @AshtonSnapp
    @AshtonSnapp Год назад +1

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

  • @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!

  • @localboxcrox
    @localboxcrox Год назад +1

    🦀

  • @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 ;)

  • @hh-dr4db
    @hh-dr4db Год назад +1

    What is that noise?

  • @RoamingAdhocrat
    @RoamingAdhocrat Год назад +1

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

  • @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!

  • @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.

  • @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!

  • @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.

  • @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!

  • @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!

  • @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 RUclips-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 RUclips 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: ruclips.net/video/sUsI6W7-d28/видео.html

  • @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().

  • @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!

  • @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

  • @YTCrazytieguy
    @YTCrazytieguy Год назад +1

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

  • @real1cytv
    @real1cytv Год назад +1

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

  • @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

    🦀