this post was submitted on 20 Mar 2024
17 points (100.0% liked)
Learning Rust and Lemmy
393 readers
1 users here now
Welcome
A collaborative space for people to work together on learning Rust, learning about the Lemmy code base, discussing whatever confusions or difficulties we're having in these endeavours, and solving problems, including, hopefully, some contributions back to the Lemmy code base.
Rules TL;DR: Be nice, constructive, and focus on learning and working together on understanding Rust and Lemmy.
Running Projects
- Rust for Lemmings Reading Club (portal)
- Rust beginners challenges (portal)
- Heroically Helpful Comments
Policies and Purposes
- This is a place to learn and work together.
- Questions and curiosity is welcome and encouraged.
- This isn't a technical support community. Those with technical knowledge and experienced aren't obliged to help, though such is very welcome. This is closer to a library of study groups than stackoverflow. Though, forming a repository of useful information would be a good side effect.
- This isn't an issue tracker for Lemmy (or Rust) or a place for suggestions. Instead, it's where the nature of an issue, what possible solutions might exist and how they could be or were implemented can be discussed, or, where the means by which a particular suggestion could be implemented is discussed.
See also:
Rules
- Lemmy.ml rule 2 applies strongly: "Be respectful, even when disagreeing. Everyone should feel welcome" (see Dessalines's post). This is a constructive space.
- Don't demean, intimidate or do anything that isn't constructive and encouraging to anyone trying to learn or understand. People should feel free to ask questions, be curious, and fill their gaps knowledge and understanding.
- Posts and comments should be (more or less) within scope (on which see Policies and Purposes above).
- See the Lemmy Code of Conduct
- Where applicable, rules should be interpreted in light of the Policies and Purposes.
Relevant links and Related Communities
- Lemmy Organisation on GitHub
- Lemmy Documentation
- General Lemmy Discussion Community
- Lemmy Support Community
- Rust Community on lemmy.ml
- Rust Community on programming.dev
Thumbnail and banner generated by ChatGPT.
founded 1 year ago
MODERATORS
you are viewing a single comment's thread
view the rest of the comments
view the rest of the comments
Please provide any feedback or thoughts on the approach and the posted code below!
My Approach
So my approach was a straight forward approach (no real algorithm) that was implemented basically as a state machine. I new ahead of time that using match statements with rust was likely a good approach so I first proto-typed my approach in python and debugged a bit there before implementing the idea in rust.
My approach was basically to go through both files simultaneously line-by-line , looking for where lines matched or differed. When lines matched/differed in the same way, they were grouped into "chunks", each of a specific kind depending on the nature of the matching/differing. They key piece to sort out was how to detect the various ways in which the two files could differ from each other (eg, addition, deletion, modification).
I settled on this idea which seems to work: A particular kind of changed-chunk is identified by (and ends with) how its final line matches with one of the initial lines of the changed-chunk. The diagram below illustrates.
Beyond this the rest was sorting out the various states the process can enter and how to move between them.
Rust programming
As for the details of using rust for this, I stumbled on a state machine pattern:
... which I found pretty nice.
I also found using an enum for the state variable along with associating data with each state a useful, flexible and elegant way to go. The program basically becomes just a single enum and the looping pattern above, along with a few data structures and some methods. Is this normal/idiomatic for rust??
The only hiccough I ran into, apart from not knowing how to do things like read standard input or a file was thinking I could trivially match on two variables at a time. I wrote about that recently here. Once the compiler got angry at me about that I got worried that I didn't know what I was doing at all, but AFAICT, it was a silly idea in the first place and best avoided for the sort of the thing I was trying to do.
Another minor issue I ran into was that I was tracking line numbers throughout the program, which were used as indices into a vector of strings, and I both wanted to do arithmetic on these numbers but also compare to the lengths of the vectors of lines. I settled on sticking with
usize
types for all such numbers, which required some conversions ... but writing this now I think I was just scared and should have just converted and stored the vector lengths to a default i32 from the beginning and made things easier ... oh well.I'll post the code in a separate comment below to keep things clean.
In my experience, this is the sweet spot for Rust programming. If you can formulate your approach as a state machine like this, then you almost always should - especially when writing in Rust.
The only times I'd pass on the pattern is if stuffing all of the ambiant state of a problem into different states of a state machine just to make the giant loop work correctly introduces too much cognitive complexity (aka makes the code too hard to read / follow).
Thanks for the feedback! What you say tracks exactly with my feelings after writing this.
I personally did encounter enough issues with the borrow checker while writing this, largely because I'm not on top of ownership and language enough, that I'm still somewhat wary of moving off of clean data flow patterns like this state machine one.
Maybe I should try re-writing it using "dumb" globals and a procedural/imperative style and see how I go?
What would you be reaching for, in terms of patterns/approaches, when you know your data flow is too messy for a state machine?
Bare
if
andloop
expressions. Basically what you described as "dumb globals and a procedural/impérative style". Of course, defining some custom types is almost always useful if not needed for "properly" handling ownership.Cheers!
Code
... continued