| |
| ▲ | jibal a day ago | parent | next [-] | | For mean spirited I would consider > There's something off-putting about how Rust people communicate. Like you're talking to people selling something, or people with ulterior motives. Which is a radically wrong description of the tone of the OP that is purportedly the reason for the comment. And for the most impressive bit of un-self-reflective projection I've seen in a long time, there's > And the way you write is extremely rude and condescending, if you do decide to phrase your comments in such a demeaning way (which I don't ever recommend), please at least be right next time. | | |
| ▲ | torginus 9 hours ago | parent [-] | | Do you use Rust in a professional capacity? Because I do, and I do because I chose it for a project over C++. Rust is much nicer in certain ways than C++ (like cargo or the whole ecosystem of packages), but it's core idea and assumption (which imo can equivalently stated as 'the borrow checker' or 'exact aliasing control') is flawed as it is, and programmers of all skill levels struggle with it for various reasons when writing programs of real-world complexity. There are 3 kinds of ways people percieve Rust - those who see it as a cool piece of tech (which I agree with), those who see it as a practical tool, and those who see liking or not liking Rust as an ideological statement. I see it as a tool. There's a lot of statements around Rust that are true in the strict factual sense, but clearly meant to be read differently. 'Free beer at the pub tonight' is a true statement even though the full truth would be 'Free beer at the bar tonight (entry fee $200)'. 'Fearless concurrency' is among these statements meant to be interpreted as making concurrent programming easier. The true statement would be 'fearless concurrency (but you might need to rewrite your program)'. |
| |
| ▲ | a day ago | parent | prev | next [-] | | [deleted] | |
| ▲ | vacuity 2 days ago | parent | prev | next [-] | | You're exaggerating heavily, which undermines your claims. While Rust claims to allow fearless concurrency, there is plenty of official documentation to show that the limitations are acknowledged. Anyone telling you Rust prevents memory leaks and race conditions is lying, straight up, and this is trivial to verify. You shouldn't be repeating it. Your comments on Send/Sync and unsafe are similarly exaggerated. I have to say, you must be interacting with Rust zealots beyond what I've ever seen, if this is truly your belief. | | |
| ▲ | torginus 2 days ago | parent [-] | | ?? Now I have to come to the defense of Rust - it does prevent memory leaks (but not space leaks where you leak memory, but it's all being referenced from somewhere). The borrow checker should also prevent race conditions (as not doing so would violate the aliasing rule) This is all provided we stay in safe Rust land, and don't do concurrency or call external APIs, but that's not a claim I'm holding against the language. This isn't the point I'm making - the issue I have is that the Rust borrow checker is not powerful enough to accept most correct programs (of real-world complexity) for various reasons. This does not mean that you can't write complex programs in Rust, it only means that most complex programs which do not have the problems Rust claims to address (successfully), have basically zero chance compiling, unleast they're written the way Rust expects them to. | | |
| ▲ | zozbot234 2 days ago | parent [-] | | > Now I have to come to the defense of Rust - it does prevent memory leaks (but not space leaks where you leak memory, but it's all being referenced from somewhere). The borrow checker should also prevent race conditions (as not doing so would violate the aliasing rule) Rc<> and Arc<> can create true memory leaks where a cycle of Rc<> or Arc<> referencing one another can stay allocated in memory even when all outside references to the objects have disappeared, so the leak cannot even be collected. This is the one thing that is not allowed to occur with a tracing garbage collector as in Fil-C. (Rust also allows leaking memory explicitly, e.g. for the purpose of passing a reference to that memory to foreign code where Rust cannot observe its lifecycle. Then in order to properly drop that memory in Rust, you have to essentially recreate that allocation from scratch.) Race conditions are a logical error that has nothing to do with the borrow checker. The borrow checker can only prevent properly defined data races, which are entirely unrelated to logical race conditions. | | |
| ▲ | torginus a day ago | parent [-] | | You are right, you can absolutely cause memory leaks with Rc, I haven't considered that. However that kind of raises an interesting point - Rc<T>::clone clearly mutates something under the hood as the reference counter is shared, however its not mut. Having something in the core language that breaks the rules and causes actual problems in practice is kind of an ill omen. And I meant data races, I have stated in my previous post, that race conditions due to issues existing outside of the language, like external libraries or network requests are not the fault of Rust. Neither are logic mistakes a programmer makes. | | |
| ▲ | zozbot234 a day ago | parent [-] | | Interior mutability is explicitly provided for in the language, and consistently marked under the hood via UnsafeCell<>. Thus, the compiler can always check whether interior mutability is possible, including wrt. reference counts. In practice, the &mut modifier has more to do with the absence of aliasing (much like *restrict in C) than mutability itself. |
|
|
|
| |
| ▲ | filleduchaos 2 days ago | parent | prev [-] | | Again to be maybe overly blunt, it's rather strange to call my comment mean-spirited and then simply repeat the exact argument I called out as being wishy-washy. The crux of what you're saying seems to be > You copy everything between threads, or try to adapt every structure that needs to be threaded with Sync, Send, Arc etc. Not very efficient use of ones time. You have not actually articulated any real problem with "Sync, Send, Arc, etc" beyond what just sounds like "but I don't wanna". Even leaving aside Sync and Send, which are constructs fairly unique to Rust, the fact that your other example of a construct you have to "try to adapt" your multithreaded code to use is Arc - quite literally the equivalent of std::shared_ptr - on its own casts heavy doubt on the seriousness of your complaint. Like, "oh no! I have to use an atomic reference counted smart pointer in my multithreaded program" is quite simply unserious as a complaint about a programming language. How exactly you think pointers should be shared between threads, then? Just passing raw pointers around, and taking responsibility any use-after-free bugs that arise because you know what you're doing and definitely aren't going to write one? Well guess what, you can do that in Rust, too (and I have done that in a few non-trivial projects), but you have to mark that obviously unsafe operation with `unsafe`. For some reason, this six-letter keyword is apparently enough to get people who allegedly know what they're doing to break out in hives, and I just do not understand it. And coming back to Send and Sync, if you understand what those traits are (versus just seeing them as something to slap on code to make the compiler stop screaming), then I'm sure you know that they are automatically derived traits. If you are having to explicitly implement them, it is because something in your structure is dubiously thread-safe - for instance, a raw pointer or a type that has been marked as thread-local. If you are that confident that you are handling whatever it is in a thread-safe manner, then what exactly is the big adaptation in the one-line implementation (each) of Send and Sync? If anything, this whole "I have to write new, explicit syntax expressing my intentions and this is The Worst and the same thing as not being to do anything at all" business just reminds me of dynamic typing diehards' complaints about static typing; just replace "using Sync, Send, Arc, etc" with "writing out type annotations". They also complain about compilers rejecting "non-trivial but correct programs" for the minor sin of not being properly annotated. > These libraries usually contain giant blobs of unsafe Rust, which isn't exactly a win for the language. You simply cannot put up this cowboy coder "I don't want to be nannied" argument and then start calling for a nanny because the keyword for "I have information that the compiler doesn't, so I'm taking the reins here" is `unsafe`. It is profoundly unserious. Same thing with this supposed overwhelming complexity of writing regular/safe multithreaded Rust, it really just sounds like wanting the language to pretend that multithreaded execution isn't complex and just handle everything about it for you as you write code as if it is single-threaded and have it just work, without having to think about the semantics. If you don't want to be nannied in that manner, then I don't understand how one can be so dissatisfied with that the language actually does (i.e. provides "certified safe - terms and conditions apply" constructs to express semantics the user is supposed to understand) that they resort to just copying everything instead and genuinely hold the opinion that the language is no different from JavaScript in that regard (a language that notoriously doesn't even have actual threads). And the comparison is plain dishonest no matter how you spin it. | | |
| ▲ | torginus a day ago | parent [-] | | Ill be extremely terse. Real world world programs usually have states where you can reach a large amount of objects. This runs into problems since you can borrow too much, and the borrow checker will push you into a corner. The solutions Rust uses to deal with this are Rc, Cell, RefCell which turn compile time borrow checks into runtime ones. However using any of these (either by you or a library you use as a dependency) disqualifies your code from being multithreaded (other than the Js worker way of running multiple copies of it on separate threads). Anyone who has written nontrival applications in Rust has encountered this. This is an issue as threading a program will require a huge rewrite. And I concede the point, multithreading is difficult - but Rust doesn't make it easier, it merely disallows most correct programs and forces you to write code in a very particular way. Thus fearless concurrency is a disingenious statement I don't fear concurrency, I fear the borrow checker. As for the cowboy/nanny argument I think this is not a good way to represent safety. Freedom comes from safety - for example, you can make pretty much anything nowadays in HTML/JS without thinking about limitations, and the end user can still be confident that your website won't compromise his system. Nannying is when you are constantly being told what you cannot do. It might not even ensure safety, but definitely restricts your freedom. And the way you write is extremely rude and condescending, if you do decide to phrase your comments in such a demeaning way (which I don't ever recommend), please at least be right next time. | | |
| ▲ | filleduchaos a day ago | parent [-] | | The very first line of the documentation of Rc (https://doc.rust-lang.org/std/rc/index.html) describes it as a single-threaded reference counting pointer. That alone should be enough indication to any dev that can actually be trusted with multithreading that it isn't going to be fit for purpose for sharing data between threads, whether the compiler yells at you about it or not. They should not need it explained to them that a program that shares non-atomically reference counted pointers between threads (while relying on their reference counting behaviour) is not a "correct program". What actually happens in practice, as you've alluded to, is that people who simply want to continue writing software the way they always have (but in Rust, whether due to FOMO or necessity) hear "use Rc/RefCell/Cell if the compiler is yelling at you" and then start slapping those constructs everywhere to avoid having to read too many of those pesky compiler errors, without ever considering or understanding what they actually are. And then when an architectural change is needed - in this case, rewriting a single-threaded program to be multithreaded - suddenly it is also the compiler's fault because the original program was not written with a single thought towards multithreading. Whether you are using a compiler that yells at you about it or not, properly threading any single-threaded program that was similarly written without concern for parallelism (say, a C or C++ program that also liberally used non-thread-safe reference counted pointers) would take a non-trivial rewrite. For some reason, the fact that Rust - a language that explicitly sells itself on catching such problems at compile time - actively surfaces the poor architecture as errors as opposed to leaving the user to hunt them down themselves is supposed to be considered Bad™. The funny thing is that there actually are real examples of problems with the borrow checker which need to be fixed by the language team (for example async closures and async Fn traits are very much a work in progress). But "I used explicitly thread-unsafe constructs and now I have to refactor my code to run properly on multiple threads" is simply not one of those problems no matter how you spin it. > Nannying is when you are constantly being told what you cannot do. It might not even ensure safety, but definitely restricts your freedom. Nannying is also literally the job of looking after a child [that isn't yours], which is a definition that in my opinion applies with users who don't want to learn how to use a tool as prescribed (this part makes perfect sense to me and is completely fair, nobody HAS to use Rust or any other language or tool regardless of what its diehard fans think), yet also want it to protect them from their own mistakes and lack of foresight when they make a mess of using it (this part makes no sense to me). To put it very bluntly (or rudely, or however else you want to read it): *all* languages (natural and programming alike) have constraints, that is what makes them languages. It's perfectly fine for the conversation to begin and end at "I don't like Rust's borrow checking rules". Sure, then don't use Rust! There are several languages that I simply don't use because I don't like something or other about them, even things as trivial as significant whitespace in Python. I don't want to deal with it so I simply...don't. But approaching a language in oppositional defiance and then complaining that you got the fight you were looking for makes little sense to me. |
|
|
|