Write Rustier Rust

Поделиться
HTML-код
  • Опубликовано: 26 июн 2023
  • Parsing in Rust, from beginner to advanced user. Covering the mental models you can use to write Rustier Rust.
    A bunch of the examples can be found here: play.rust-lang.org/?version=s...
    gist: gist.github.com/rust-play/ce1...
  • НаукаНаука

Комментарии • 79

  • @Dr4zh4r66
    @Dr4zh4r66 Год назад +64

    Great explanations!
    I would recommend using fewer transitions from Code + Thumbnail to only you without the code. It makes it harder to follow, especially with the transition effects.

  • @gajop
    @gajop Год назад +89

    Unfortunately this was difficult to follow as code would be displayed for only brief periods.
    I think it's fine to always show code and reduce screen switches - users are unlikely to get bored.
    Regarding content, I'd like to see a perf or "panic-safety" comparison. Is there any difference between these solutions?

    • @chrisbiscardi
      @chrisbiscardi  Год назад +9

      I usually error on the side of letting people pause the video if they want to read it in depth. There is also code linked below in the description. (there would be a blog post as well to go with the video, but I'm re-launching the site the blog post would be on right now, so I'll have to link that later).
      As for panics, none of the options should panic. The big difference between the options that use .unwrap() and the ones that don't is whether the programmer has to keep the potential for a panic in mind while programming. A panic would only happen in those cases if the program was modified in the future to remove the starting assumptions, for example.
      perf could make an interesting video itself. The options weren't made with specific perf requirements in mind, but we could evaluate their runtime and heap usage to see if its worth changing anything.

    • @wojtekkrupski8583
      @wojtekkrupski8583 Год назад +34

      @@chrisbiscardi Frequent screen switches are just annoying. The content is very interesting, but I had difficulty perceiving it because of these

    • @toadtws
      @toadtws 4 месяца назад

      @@chrisbiscardiI agree with the feedback. I wonder if highlighting what has changed would help. You were using selection when speaking about bits of each new version, but it was hard to see what all had changed. What if you leave out the text to parse and give before and then after with diff-like output to clarify changes?

  • @myronkipa2530
    @myronkipa2530 Год назад +25

    Here's how I'd do the problem:
    fn paragraphs(input: &str) -> Vec {
    input
    .split("

    ")
    .map(|p| p.replace("
    ", " "))
    .collect()
    }

  • @kurt7020
    @kurt7020 Год назад +72

    At first I wrote clunky code. I learned more. I wrote clever code. I learned even more. Years later *I write clunky code on purpose*. Everyone on my team can trivially read it. Six months from now, I can trivially read it.

    • @Chronozia
      @Chronozia 9 месяцев назад +12

      My old CS Prof's motto was
      "Code should be correct, clear and efficient. Prefer simple. Avoid clever"
      Years later I realize how much weight that carries

    • @twothreeoneoneseventwoonefour5
      @twothreeoneoneseventwoonefour5 7 месяцев назад +6

      At first my pants were always dirty. I became more careful. Cleaned my clothes. Became even more careful. Years later, I *stopped caring about all the dirt on my pants* and purposefully run in dirt puddles. My friends were relieved that I didn't change, and that there is always someone beneath them as a human. Six months from now, I can trivially walk naked in the daylight.

    • @davidrudpedersen5622
      @davidrudpedersen5622 2 месяца назад

      ​@@twothreeoneoneseventwoonefour5wack analogy

    • @twothreeoneoneseventwoonefour5
      @twothreeoneoneseventwoonefour5 2 месяца назад

      @@davidrudpedersen5622 wack reply

    • @T1Oracle
      @T1Oracle 17 дней назад

      ​@@davidrudpedersen5622it was funny though 😂

  • @Galakyllz
    @Galakyllz Год назад +27

    This video was awesome! You did a great job of walking from "acceptable" to "ideal", explaining why we might make those changes. I would love to see more videos like this, demonstrating some nice features from useful crates as you make the code better.

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

      glad you enjoyed it! I'll have to come up with some other useful crates to make examples for.

  • @pebaz
    @pebaz 10 месяцев назад +13

    I could watch a ton of videos like this.
    One idea: teach the standard library by refactoring imperative code into the stdlib alternatives.

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

    Very informative video on just writing code that works and the ideal way to to write code(that also works). Got to learn a thing or two and also get to know about crates I never knew about before. Keep making more videos like this. We appreciate it

  • @bryanleebmy
    @bryanleebmy 10 месяцев назад +12

    This is less "Rustier" Rust and more of a nom tutorial.
    Also, it seemed to me that the more Rusty the code got, the more unreadable and opaque it became.
    Anyone can understand for loops and if statements. Fewer can understand fold / reduce. Even fewer will understand group_by and coalesce and all of the other itertools methods.
    Even if you understand the functional concept, you'll still have to reach for documentation to make sure the programmed behaviour lines up with your expectation.

    • @chrisbiscardi
      @chrisbiscardi  10 месяцев назад +1

      The fact that you happen to be heavily exposed to for loops and not exposed to other approaches as much doesn't mean that fewer people can understand a fold. A group_by is not harder to understand than an equivalent for loop. Unfamiliar I could totally understand, but not harder... and this is kind of the point. You're clearly familiar with for loops and are fine using them to the exclusion of other approaches... but you should be able to read and use other functions from the standard library that better match what you're trying to achieve rather than re-implementing that functionality over and over using for loops.
      The core point of the video is that there are functions which do what you're trying to do and you should go look for them. Whether that's finding a new function you're unfamiliar with in itertools, a function on a type in the std lib, or in a third party crate like nom. for loops are fine, but they are far from the best solution to many problems, especially if those for loops access and mutate surrounding variables and leak into the rest of the program.

    • @bryanleebmy
      @bryanleebmy 10 месяцев назад +7

      ​ @chrisbiscardi I don't disagree that more people are familiar with for loops, but that's kind of the whole point.
      The fact that one concept, the for loop, has become so universally understood speaks to the flexibility and readability of the for loop. I'm familiar myself with the basic iterator functions like map, filter, reduce, but when the toolkit goes from 1-2 concepts to 20+ concepts, I'd argue that we've gone from simple and readable code to short but obtuse code.
      It is probably a philosophy difference, but idiomatic Rust code as you described it just looks much harder to read and write. We could argue that for loops are more error prone, but I strongly believe that that is equally true for iterator concepts, especially when you start introducing so many operators and combinators.
      Even in your video, you've kind of proven that point: you brought up three different methods of doing the same thing: fold, group_by, and coalesce. Writing Rustier Rust like you described becomes less about the business logic and more about arguing over which iterator concept is "better".

  • @That_Guy_You_Know
    @That_Guy_You_Know Год назад +10

    @5:41 I agree with your reasoning here. It may be nice to use expect() vs unwrap() so if the panic is reached due to the unwraps it can include your reasoning.

  • @dj-maxus
    @dj-maxus Год назад +4

    You basically introduced nom parser to me in your "advent of code" series. Thanks!

  • @MichaelKefeder
    @MichaelKefeder Год назад +11

    at 8:40 it's because concatenating Strings needs allocation, and the definition of coalesce enforces the same type for the closure args and for the closure's return types, hence we already need to feed it Strings instead of &str. I would however use !s.is_empty() consistently in this example, as checking len() for not zero is less readable ;)

  • @Shaunmcdonogh-shaunsurfing
    @Shaunmcdonogh-shaunsurfing 11 месяцев назад

    Perfectly well put together video. Thank you.

  • @programming5274
    @programming5274 Год назад +8

    5:29 We don't need to make an anonymous function, we can just pass in the is_empty function: is_some_and(String::is_empty)

  • @hexomega9445
    @hexomega9445 4 месяца назад

    Nice choices! Thanks for sharing!

  • @JagaSantagostino
    @JagaSantagostino Год назад +5

    Great video! A feedback to have video like that more enjoyable. The parts where you are explaining going fullscreen with webcam, it would be great to see a diff of the change (git style) it makes it much easier so understand at a glance.
    Have a nice day and thanks again!

  • @ohchristusername
    @ohchristusername Год назад +9

    Solid information!
    I think it would be much easier to follow the information in the video if you didn't hide the code so quickly in certain parts. Having to go back and pause isn't ideal, and having to only listen to the audio at times feels pretty meaningless.

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

    Very useful, thanks. It will be great to know more bout _nom_ parser combinator, through an example. 👍

  • @CuriousSpy
    @CuriousSpy Год назад +4

    i got sick because of this camera shaking. Thanks for video

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

    Audio recorderoutside was impressive good and crisp 🙌

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

    I felt like I'm in a Flutter's official tutorials, switching screens doesn't make difficult to follow for me but might be for others.

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

    Gonna have to watch this one a couple times hahah, tons of info. I guess you could say I'll... iterate :D

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

      feel free to drop any questions you have :)

  • @Chastor97
    @Chastor97 9 месяцев назад

    I have implemented group_by algorithm at my js job some time age. It's about cards that are grouped into blocks by their background

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

    Very cool analysis of non-idiomatic code and its improvements!

  • @user-xi6tu9lb5n
    @user-xi6tu9lb5n 10 дней назад

    I wonder if by binary sniffing we would find that the beginner code is the most concise.

  • @Molly-nr2jc
    @Molly-nr2jc Год назад

    Great videos thanks a lot

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

    Nice.
    Ideally, `tuple((newline, newline))` should be its own parser, `blank_line` or `break`, since you may have additional white space between line breaks which aught to be ignored.

  • @DJenriqez
    @DJenriqez Год назад +8

    This is like Wolfenstein, difficulty selection, first you have agent Blaskowicz with teether, normal guy, and masochist view, with blood over his face,... it has same energy as this video :D :D But fun aside, I would prefer, the first version of code. Yes the second part is more "rusty" (maybe also performant in 0.00001 milis, who knows,..), but I can't imagine junior (or senior migrating to rust) coming to work on my project and seeing it. Also when someone works on multiple projects, in multiple languages, its better to unity code style as much as possible, even in price of violating the given language rules,..... (which is possible with first style almost in every language).

    • @2raddude
      @2raddude Год назад

      100% couldn't agree more

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

      heh, the difficulty selection/gradient of options was definitely the goal :D
      I'm not sure which version you're referring to as "the second part". Are you saying that using .fold() is too much for a senior engineer? or are you referring to using nom at the end?

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

      @@chrisbiscardisecond part i mean second part of video , “rusty” code alternative. The whole, i dont know how to call it “get” instead of “push” architecture,.. with iter, collect,.. like its not hard of course, but when you are old school developer, you dont get a lot of simmilar aproaches in schools with c# and java,… (yeah today those languages has it too in never versions)

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

      @@DJenriqez so you are saying that .fold() is too much for a senior engineer? I think we disagree on that at least.

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

      @@chrisbiscardi Sorry I didn`t saw the "fold" alternetive, I was jumping across the video.... :D :D 1-2 fine, 3th is hard... not saying its exactly hard for senior, but not so easy to mount on new project. For example I'm c++ / typescript / python dev, and I had to jump on c# project which I was able over a night,...

  • @adicide9070
    @adicide9070 10 месяцев назад +1

    Yeah this is why I like Go.

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

    This is excellent content 🙌

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

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

    types ❤

  • @OlivierGeorg
    @OlivierGeorg 5 месяцев назад

    If you have multiple empty lines, won't that create empty paragraphs?

    • @chrisbiscardi
      @chrisbiscardi  5 месяцев назад

      Not sure exactly which part you're referring to, but for the nom version its a trivial fix to accommodate that (many1(newline) instead of newline): play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=c7873701298b352fca56596eaf53b25c

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

    fold or reduce or inject

  • @i--i4933
    @i--i4933 Год назад

    question
    what editor/ide are you using?

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

      VSCode

    • @i--i4933
      @i--i4933 Год назад

      @@chrisbiscardi thanks
      it looks so much cleaner than my version of it :)

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

      @@i--i4933 I remove all of the optional UI elements and a lot of the popups/auto intelligence/etc in the settings so that it works better for presenting code

    • @i--i4933
      @i--i4933 Год назад

      @@chrisbiscardi cool, your vids are great , really helped me with understanding rust
      much love

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

    The advanced code just exploded in complexity and introduced an external library.
    I would prefer the iterator solution on lines 25-31at 7:45, but with ```lines=input.trim().lines()``` instead of using an external crate to split.
    Or ```input.trim().split("

    ").map(|p| p.replace("
    ", " ")).collect()```, which was already suggested in the comments. The "Windows newline issue" is a fair counterpoint though, so a solution that can utilize ```input.lines()``` would be preferable IMO.

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

      yes, you can absolutely overfit the problem with a specific solution. As I mentioned in the video though, this is a parsing problem usually contained as part of a larger parser, such as markdown, which would require extending the parser with both inline and other block level content.
      Dependencies are good and cargo/the ecosystem is one of Rust's major strengths. You can always spend time rewriting a dependency into a more fitted solution, but you can't get the time you spent rewriting pre-existing functionality back.
      This is only an increase in complexity when viewed from the over-fitted "this passes the one test in the video" viewpoint. The complexity is reduced by using the external library if you consider that you'll have to build more parsing functionality in addition to this one test example. At which point the benefit of building parsers that compose together with a familiar function signatures and patterns outweighs the need to make a new decision about how to parse every new piece of functionality.

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

      What if your input starts with two new lines? or what if your have more than two new lines between paragraphs? Now suppose you want to add the ability to parse anything else, say a code block (that may have multiple subsequent newlines). How do you handle that? I think the conclusion of the video is on point. Basically, anything is fine if it fits your requirements, but it's always good to know more than one solution to a problem. That one liner is fine if you're certain that you're not gonna want more complexity and if you're constraining your input a bit, while the composable parsers approach is very flexible at the expense of having some learning curve.

  • @dzarko55
    @dzarko55 6 месяцев назад

    The way I’d do it intuitively is
    fn paragraph(inp: &str) -> Vec {
    let mut lines = inp.lines();
    iter::from_fn(move || {
    (!lines.is_empty).then-some(lines.by_ref().take_while(|x| !x.is_empty()).collect::())
    }).collect()
    }
    iter::from_fn is just a more readable way of writing (0..).map(|_| …), ie an iterator where you selectively advance another iterative to generate values.
    Alternatively, I’d replace the return Vec with return impl Iterator, so the caller can decide to collect or use the Iterator however they want.
    I haven’t checked this, might well not work.

    • @chrisbiscardi
      @chrisbiscardi  6 месяцев назад

      The approach you've taken here is the group_by example from the video but slightly obscured (and also not working but I'm going off the gist of what you're intending).
      input
      .lines()
      .group_by(|line| !line.is_empty())
      .into_iter()
      .map(|(_key, mut group)| group.join(" "))
      .filter(|s| !s.is_empty())
      .collect();

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

    Rust. Ruster. Rustest.

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

    This feels like a regex problem, why would you prefer this solution over regex? The approach to "rustifying" code in a broader sense was cool though

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

      Regex tend to be "write only", especially as you get into larger regex applications, while parser combinators are individually testable/composable functions that can hold their own documentation and such.

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

      @@chrisbiscardi ah I see, more scalable, more modular. Describing regex as write only made it make sense to me, I wouldn't want to try merging two complicated expressions

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

      You may not have heard the apocryphal advice about regexes:
      1. You have a problem.
      2. You think, "I know! I can use a regex for this!"
      3. Now you have two problems.
      :-)

  • @mochou-p
    @mochou-p 4 месяца назад +2

    1:15 poor lines.. 💔

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

    Good video but... If you are explaining code, remove video effects, quit hiding the code all the time, slow down your presentation.

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

    Rusty Luke Smith

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

    great video to only reduced by way too many sliding transitions, please stop, very hard to follow

  • @stephennelson-smith3312
    @stephennelson-smith3312 5 месяцев назад

    Excellent material, and very interesting and informative, but, as a person with an ADHD brain I found this painful to watch - the frequent changes and transition effects made it unbelievably hard to follow, and I had to give up after about 5 mins. I watched those 5 mins twice because the content itself was very good, but actually trying to watch it was so uncomfortable, I had to basically close my eyes and just listen. Normally I do better with videos than blog posts, but this was too much for me. Please don't take this as a criticism - I may not be representative of your target audience (although I suspect neurodivergent folk are particularly well represented among the set of people watching youtube videos about Rust programming), but perhaps bear it in mind for future productions.

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

    What about
    input.split("

    ").map(|p| p.split('
    ').join(" ")).collect()

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

      its fine for the specific case in the video, but harder to extend to be platform independent (
      vs
      ) and harder to use if there are items inside it like markdown would have (todo items, etc).
      I'd still replace .split('
      ') with .lines() in this approach, as it accounts for
      and