6 ms·
can I poll the audience of seasoned rust devs: how do you deal with the borrow checker and lifetimes? do you simulate both in your head before writing your code
by throwlaplace 7y ago
can I poll the audience of seasoned rust devs: how do you deal with the borrow checker and lifetimes? do you simulate both in your head before writing your code or do you just let the compiler yell at you and then silence it by fixing bugs?
I ask because I've written some trivial rust code (a little TUI client for a database) and while it was mostly fine, I didn't feel myself absorbing the rules by osmosis (I had to wait for the compiler to yell at me and then wrestle).
- burntsushi 7y agoI'm not sure if it's a simulation so much as the rules just become normal constraints you use when writing code. It is super rare for me these days to write any line of Rust code that makes the borrow checker complain in a way that surprises me. It took me a while to get to that point. I don't remember how long though.
- throwlaplace 7y agoany suggestions for exercises that drill this in? I'm going through the linked list book but it's still not completely transparent for me.
- burntsushi 7y agoNot really. Pick a project and start building. At least, that's my learning style. Reading things like the linked list book is great, but eventually, you probably have to put it to practice in order to really learn it (like most things).
- steveklabnik 7y agoI would like to second everything you've said here, and add a few things: 1. If you are feeling stuck, please reach out on users.rust-lang.org or discord.gg/rust-lang. We're here to help! 2. If you're feeling really stuck, maybe take a break and come back to Rust in a few months. A number of people have given up on Rust in frustration, came back after a significant amount of time, and then said "why did I think that was so hard before?" 3. Don't worry about a few calls to clone when you're getting started; it's better to have a working program that does some extra copying than it is to not have a program at all. 4. Especially when starting out, you almost always want structs to own their data. Don't use references as struct members unless you're absolutely sure that's what you want. Advice #3 helps with this. 5. I think one of the biggest mindsets that can set you up for failure with Rust is "The compiler says no, how do I get it to do what I want anyway" instead of "The compiler says no, what is it telling me, and how can I work with it instead?" Especially if you come from an OO heavy background, you may need to change the patterns that you reach for initially. Yes, you can write any style in any language, but Rust pushes you towards its idioms much more strongly than other languages do.
- burntsushi 7y agoHah yes, this is a MUCH better answer. Thank you. :-)
- steveklabnik 7y agoNaw I think you hit the most important bits right up front :)
- CameronNemo 7y ago>discord.gg/rust-lang Why not plug the rust channel on Matrix?
- steveklabnik 7y agoI only plug: * Things that are run by the project * Things that I use I have no idea if the Matrix channel is any good or not, so I cannot recommend it.
- CameronNemo 7y agoFair enough. Hope you do get a chance to check out the Matrix channel! (#rust:mozilla.org)
- adamch 7y ago+1 to the Rust Discord being _really_ helpful. If you can provide an example on play.rust-lang.org, someone will definitely help you.
- aganame 7y agoThe Rust channels on Matrix and oftc irc are really helpful as well :) For drills, I recommend exercism.io in practice mode (mentor/student ratio is pretty bad). After working on your own solution for a while, then checking how the others solved it... priceless. Somebody almost always figured out an objectively better solution.
- hechang1997 7y agoI found the "Too Many LinkedList" tutorial is very helpful. Try to follow the tutorial by writing your own code.
- GolDDranks 7y agoLifetimes are not actually that hard: it's mostly stack discipline, with some escape hatches. The compiler yelling at me is mostly stupid, surface syntax like things, but that's because I've learnt naturally to structure my code in a way that makes sense with stack discipline. Over 5 years of Rust experience, 2 of which are professional.
- hathawsh 7y agoThe key, I think, is to figure out which kinds of Rust patterns are ambitious and efficient if they work, versus patterns that are easy to write and unlikely to fail. It's tempting to use references everywhere possible for efficiency, but Rc, Arc, Cell, RefCell, Mutex, and other smart pointer types can get you out of a jam. Sometimes you just have to bite the bullet and clone things until you've figured out a better way. Looking back at the very first Rust module I wrote, it's actually not half bad. I thought it was bad at the time because I was continuously fighting the borrow checker, but now I see that the borrow checker led me toward fairly idiomatic Rust patterns. BTW, if you're coming from Javascript or Python, the closest thing to a JS/Python string in Rust is Rc<String> or Arc<String> (depending on whether your code is multithreaded.) I don't want to admit how long it took me to figure that out and I think that little bit of wisdom ought to be featured prominently in the Rust book. :-)
- saagarjha 7y agoI would steer you away from Rc and Arc unless you know you need them.
- hathawsh 7y agoPerhaps. I can think of a couple reasons to steer people away from Rc/Arc: they are less efficient than references and they don't support cyclic garbage collection. On the other hand, Rc/Arc are very helpful for newcomers coming from garbage collected languages and they can be more efficient than cloning. If I asked an employee to convert some high level module to Rust and that employee used a lot of Arcs where they weren't really necessary, I would say that employee had done a reasonably good job.
- pjmlp 7y agoThey are unavoidable with most GUI bindings on Rust, actually it is a plethora of Rc<RefCell<>> across the code.
- _never_k 7y agoBefore rust, I would incrementally evolve an incomplete design into a complete design (building a tree by building leaves, branches, and a trunk and then assembling them.) In rust, my early incremental versions would have lifetime issues that I used to not worry about until later. Now I start with a very small complete version that I make bigger (building a tree by increasing the size of a sapling.) I do everything this way now (JS, python, etc...)
- ufmace 7y agoI honestly haven't felt like it was much of a problem. IMO, the main thing to understand is that Rust strongly prefers that each instance has one and only one owner at any time, and any references to that object should only exist for a strictly constrained amount of time. This is the preferred style, and doing anything else, including some patterns common in other languages and OOP, will be very painful. Don't be afraid to throw clone() around with reckless abandon any time references get confusing, most things are cheap and fast to clone, and it's generally better to get your program working now and then optimize as needed, rather than try to figure out how to handle a weird case.
- _-___________-_ 7y agoWriting rust since ~2016, doing a lot of async/await and multithreaded stuff and using explicit lifetimes quite often. At the beginning it was a case of write the code, then see how the borrow checker complains and fix it. Now that I understand the semantics intuitively, for the last year or so, it's very rare for the compiler to complain about anything. I guess I've internalised the semantics -- they're not exactly arbitrary, mostly the lifetime rules just follow from what you should be doing anyway. One thing I would encourage (and this applies in general) is trying to understand _why_ the compiler is complaining about some code you wrote before attempting to "make the error go away". Don't just hammer away until you make it work; that's not how you learn. I've seen a lot of Rust code that's full of unnecessary use of Cell, Rc, etc because people didn't take the time to understand the semantics and just reached for ways to "make the errors go away".