3 ms·
> Some very solid argument here. However, as already implied in my article, you can get most of the guarantees without losing your sanity. I think this is part
by saghm 1y ago
> Some very solid argument here. However, as already implied in my article, you can get most of the guarantees without losing your sanity.
I think this is part of why your article is causing a strong reaction from a lot of people; quite a lot of the justification for your point of view is left implied, and the concrete examples you do give about Rust (e.g. `Arc<Mutex<Box<T>>>>` and `.unwrap`) are hard not to see as straw men when plenty of people write Rust all the time without needing to rely on those; it turns out it's also possible to get more reliability out of Rust for those people without losing their sanity.
Most of the opinions you give are hard to distinguish from you personally not finding Rust to provide a great experience, which is totally valid, but not really indicative of "core problems" in the language. If you instead were making the argument of why you don't personally want to write any code in Rust, I don't think I'd have much criticism for your point of view (even though I wouldn't find much of it to apply to me). Then again, the article starts off with a statement of previously having made an intentionally provocative statement purely to try to compensate for a perceived bias in others, so maybe I'm just falling for the same bit by trying to engage the article as if it's serious.
- adastra22 1y agoAlso the argument with `Arc<Mutex<Box<T>>>>` boils down to "Rust makes it hard to work with automatic reference-counted shared mutable heap-allocated state." In which case... mission accomplished? Rust just made explicit all the problems that you still have to deal with in any other language, except dealing correctly with all that complexity is such a pain that you will do anything you can to avoid it. Again, mission f#*@ing accomplished. Maybe you DON'T need that state to be shared, reference-counted, or heap allocated. Maybe you can refactor your code to get rid of those annoyingly hard to deal with abstractions. And you end up with better, more reliable, likely faster code at the end of it. So many times I've tried to do something in Rust the old fashioned way, the way I have always done things, and been stopped by the compiler. I then investigate why the compiler/language is being so anal about this trivial thing I want to do.. and yup, there's a concurrency bug I never would have thought of! I guess all that old code I wrote has bugs that I didn't know about at the time. There are basically two reactions people have to this situation: (1) they're thankful that they learned something, their code is improved, and go about their day learning something new; or (2) feel frustrated and helpless that the old way of doing things doesn't work, and rage-quit to go write a "WHY RUST IS THE WORST THING SINCE MOSQUITOS" blog article.
- bryanlarsen 1y agoNit: it doesn't make it hard, it makes it ugly and explicit. `Arc<Mutex<Box<T>>>>` is not hard to use, it's just annoyingly verbose and ugly. That's a low level construct, there are much nicer higher level sharing constructs, like channels. Mission accomplished.
- adastra22 1y agoIt is hard to use because you can’t just access the shared state. You have to annoyingly lock it, handle the guard object, etc. Each one of those layers has protocols.
- bryanlarsen 1y agoOf course you have to lock a mutex. You'd have to do that no matter the language, right? And that's what I meant by verbose/ugly. Each of those steps is usually an if let / else error. None of those steps are hard, but you have to do them every time.
- adastra22 1y agoOh, plenty of people access shared state without proper locks all the time. Even experienced developers.
- bryanlarsen 1y agoHeh. You're pedantically correct, the best kind. I meant "have to" in terms of "for correct operation you must" not "the compiler forces you to" since the latter isn't a thing in some languages.
- saghm 1y agoYeah, this pretty much summarizes my experience. In most situations, the actual information I need to share between different contexts is quite small, and using a channel ends up being pretty clean. There are still times I need an actual reference counted wrapper around a mutex, but they're the exception rather than the norm, and even then, there are often ways you can reduce the contention (e.g. if `T` is a type you can clone, and you only need a snapshot of the current state of the data rather than preventing changes while processing based on that snapshot, you can just clone it, drop the mutex guard, and then proceed without needing to worry about borrows).