4 ms·
> Pointers don't stop being dangling just because they're stashed in a deeply nested data structure or passed down in a way that [[lifetimebound]] misses This
by germandiago 2y ago
> Pointers don't stop being dangling just because they're stashed in a deeply nested data structure or passed down in a way that [[lifetimebound]] misses
This is the typical conversation where it is shown what Rust can do by shoehorning: if you want to borrow-borrow-borrow from this data structure and reference-reference-reference from this function, then you need me.
Yes, yes, I know. You can also litter programs with globals if you want. Just avoid those bad practices. FWIW, references break local reasoning in lots of scenarios. But if you really, really need that borrowing, limit it to the maximum and make good use of smart pointers when needed. And you will not have this problem.
It looks to me like Rust sometimes it is a language looking for problems to give you the solution. There are patterns that are just bad or not adviced in most of your code and hence, not a problem in practice. If you code by referencing everything, then Rust borrow-checker might be great. But your program will be a salad of references all around, which is bad in itself. And do not get me started in the refactorings you will need every time you change your mind about a reference deep somewhere. Bc Rust is great, yes, you can do that cool thing. But at what cost? Is it even worth?
I also see all the time people showing off the Send+Sync traits. Yes, very nice, very nice. Magic abilities. And what? I do my concurrent code by sharing as little as possible all the time. So the patterns of code where things can be messed up are quite localized.
Because of this, the borrow checker is basically something that gets a lot in the way but does not add a lot of value. It might have its value in hyper-restricted scenarios where you really need it, and I cannot think of a single scenario where that would be really mandatory and really useful for safety except probably async programming (for which you can do structured concurrency and async scopes still in C++ and I did it successfully myself).
So no, I would say the borrow checker is a solution looking for problems because it promotes programming styles that are not clean from the get go. And only in this style it is where the borrow checker shines actually.
Usually the places where the borrow checker is useful has alternative coding patterns or lifetime techniques and for the few ones where you really want something like that, probably the code spots are small and reviewable anyway.
Also, remember that Rust gives you safety from interfaces when you use libraries, except when not, bc it basically hides unsafe underneath and that makes it as dangerous as any C or C++ code (in theory). However, it should be easier to spot the problems which leads more safety in practice. But still, this is not guaranteed safety.
The borrow checker is a big toll in my opinion and it promotes ways of coding that are very unergonomic by default. I'd rather take something like Swift or even Hylo any day, if it ever reaches maturity.
- nostradumbasp 2y agoIn general I view the borrow checker as a good friend looking over my shoulder so I don't shoot myself in the foot in production. 99 times out of 100 when the borrow checker complains it's because I did something stupid/wrong. 0.99 times out of 100 I think the borrow checker is wrong when I am in fact wrong. 0.01 times out of 100 the borrow checker fumbles on a design pattern it maybe shouldn't so I change my design. Usually my life is way better for changing the design after anyways. The thing is, you don't need to have refs of refs of refs of refs of refs. You can clone once in a while or even use a smart pointer. You'll find in 99.99% of cases the performance is still great compared to a GC language. That's a common issue for certain types of people learning how to write Rust. I can't think of any application that needs everything to be a reference all the time in Rust. As far as "mandatory" goes for choosing a language. We can all use ASM, or C, write everything from scratch. It's a choice. Nothing is mandatory. No one is saying you HAVE to use Rust. Lots of people are saying "when I use it my life is way better", that's different. There was a recent post here where people say they don't use IDE's with LSP or autocomplete. A lot of people are going to grimace at that, but no one is saying they can't do that.
- pornel 2y ago> I also see all the time people showing off the Send+Sync traits. Yes, very nice, very nice. Magic abilities. And what? I do my concurrent code by sharing as little as possible all the time. So the patterns of code where things can be messed up are quite localized. They check whether your code really shares as little as you think, and prevent nasty to debug surprises. The markers work across any distance, including 3rd party dependencies and dynamic callbacks, so you can use multi-threading in more situations. You're not limited to basic data-parallel loops. For example, it's immensely useful in web servers that run multi-threaded request handlers that may be calling arbitrary complex code. > places where the borrow checker is useful has alternative coding patterns There's a popular sentiment that smart pointers make borrow checker unnecessary, but that's false. They're definitely helpful and often necessary, but they're not an alternative to borrow checking. Rust had smart pointers first, and then added borrowing for all the remaining cases that smart pointers can't handle or would be unreasonable to use. Borrowing checks stack pointers. Checks interior pointers to data nested inside of types managed by smart pointers (so you don't have to wrap every byte you access in a smart pointer). It allows functions safely access data inside unique_ptr without moving it away or switching to shared_ptr. Prevents using data protected by a lock after the lock has been unlocked. Prevents referencing implicitly destroyed temporary objects. Makes types like string_view and span not a footgun. > the borrow checker is basically something that gets a lot in the way This is not the case for experienced Rust users. Borrow checker is a massive obstacle to learning and becoming fluent in Rust. However, once you "get" it, it mostly gets out of the way. Once you internalise when you can and can't use borrowing, you know how to write code that won't get you "stuck" on it, and avoid borrow checking compilation errors before they happen. And when something doesn't compile, you can understand why and how to fix it. It's a skill. It's not easy to learn, but IMHO worth learning more than C++'s own rules, Core Guidelines, UB, etc. that aren't easy either, and the compiler can't confirm whether you got them correct.