Here's how I'd do the problem: fn paragraphs(input: &str) -> Vec { input .split(" ") .map(|p| p.replace(" ", " ")) .collect() }
@chrisbiscardi Жыл бұрын
How would you handle windows line endings?
@myronkipa2530 Жыл бұрын
@@chrisbiscardi replace(" ", " ") in the beginning 😁
@burgerking4for410 Жыл бұрын
Was looking for this
@kurt7020 Жыл бұрын
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 Жыл бұрын
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 Жыл бұрын
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.
@davidrudpedersen56226 ай бұрын
@@twothreeoneoneseventwoonefour5wack analogy
@twothreeoneoneseventwoonefour56 ай бұрын
@@davidrudpedersen5622 wack reply
@T1Oracle5 ай бұрын
@@davidrudpedersen5622it was funny though 😂
@Galakyllz Жыл бұрын
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 Жыл бұрын
glad you enjoyed it! I'll have to come up with some other useful crates to make examples for.
@bryanleebmy Жыл бұрын
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 Жыл бұрын
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 Жыл бұрын
@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".
@gajop Жыл бұрын
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 Жыл бұрын
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 Жыл бұрын
@@chrisbiscardi Frequent screen switches are just annoying. The content is very interesting, but I had difficulty perceiving it because of these
@toadtws9 ай бұрын
@@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?
@shinobiwannabe4 ай бұрын
Bruh just press pause???
@Dr4zh4r66 Жыл бұрын
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.
@pebaz Жыл бұрын
I could watch a ton of videos like this. One idea: teach the standard library by refactoring imperative code into the stdlib alternatives.
@That_Guy_You_Know Жыл бұрын
@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.
@MichaelKefeder Жыл бұрын
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 ;)
@programming5274 Жыл бұрын
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)
@JagaSantagostino Жыл бұрын
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!
@superhero-studiosАй бұрын
I really like this video format by the way. I hadn't seen you do it before -- but hope to see you do more.
@chrisbiscardiАй бұрын
thanks, I think the format is good, there are things I'd like to improve upon for the next time I use it.
@randomhunter47 Жыл бұрын
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
@allxrise Жыл бұрын
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.
@dj-maxus Жыл бұрын
You basically introduced nom parser to me in your "advent of code" series. Thanks!
@ohchristusername Жыл бұрын
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.
@CuriousSpy Жыл бұрын
i got sick because of this camera shaking. Thanks for video
@JagaSantagostino Жыл бұрын
Audio recorderoutside was impressive good and crisp 🙌
@DJenriqez Жыл бұрын
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 Жыл бұрын
100% couldn't agree more
@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 Жыл бұрын
@@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 Жыл бұрын
@@DJenriqez so you are saying that .fold() is too much for a senior engineer? I think we disagree on that at least.
@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,...
@Chastor97 Жыл бұрын
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
@JasonIvey-u4n5 ай бұрын
I wonder if by binary sniffing we would find that the beginner code is the most concise.
@nirmalyasengupta6883 Жыл бұрын
Very useful, thanks. It will be great to know more bout _nom_ parser combinator, through an example. 👍
@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.
@TheInspctrcat Жыл бұрын
Very cool analysis of non-idiomatic code and its improvements!
@mochou_p9 ай бұрын
1:15 poor lines.. 💔
@Shaunmcdonogh-shaunsurfing Жыл бұрын
Perfectly well put together video. Thank you.
@Taernsietr Жыл бұрын
Gonna have to watch this one a couple times hahah, tons of info. I guess you could say I'll... iterate :D
@chrisbiscardi Жыл бұрын
feel free to drop any questions you have :)
@hexomega94459 ай бұрын
Nice choices! Thanks for sharing!
@adicide9070 Жыл бұрын
Yeah this is why I like Go.
@turun_ambartanen Жыл бұрын
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 Жыл бұрын
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 Жыл бұрын
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.
@OlivierGeorg10 ай бұрын
If you have multiple empty lines, won't that create empty paragraphs?
@chrisbiscardi10 ай бұрын
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
@dzarko5511 ай бұрын
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.
@chrisbiscardi11 ай бұрын
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();
@i--i4933 Жыл бұрын
question what editor/ide are you using?
@chrisbiscardi Жыл бұрын
VSCode
@i--i4933 Жыл бұрын
@@chrisbiscardi thanks it looks so much cleaner than my version of it :)
@chrisbiscardi Жыл бұрын
@@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 Жыл бұрын
@@chrisbiscardi cool, your vids are great , really helped me with understanding rust much love
@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 Жыл бұрын
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_ Жыл бұрын
@@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 Жыл бұрын
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. :-)
@martinbecker1069 Жыл бұрын
fold or reduce or inject
@sot_dev3 ай бұрын
I don't think using iterator determines a beginner or advance code. IMO
@zhahirzulkufli1861 Жыл бұрын
@alexanderoransky7601 Жыл бұрын
Good video but... If you are explaining code, remove video effects, quit hiding the code all the time, slow down your presentation.
@Molly-nr2jc Жыл бұрын
Great videos thanks a lot
@zahash1045 Жыл бұрын
Rust. Ruster. Rustest.
@ThrashAbaddon Жыл бұрын
This is excellent content 🙌
@ayoubelmhamdi7920 Жыл бұрын
types ❤
@dragonmax2000 Жыл бұрын
great video to only reduced by way too many sliding transitions, please stop, very hard to follow
@pwnwriter Жыл бұрын
Rusty Luke Smith
@stephennelson-smith331210 ай бұрын
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 Жыл бұрын
What about input.split(" ").map(|p| p.split(' ').join(" ")).collect()
@chrisbiscardi Жыл бұрын
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