37 ms·
My negative views on Rust
- option_greek 5y agoAnother 'I don't like Rust - I don't use it - but I like writing blog posts about it' article. I wonder if there are more lines written about liking and disliking Rust in the world than actual Rust code at this point.
- imron 5y ago> Another I don't use it - but I like writing blog posts about it' article. Another “I didn’t read the article but I like writing replies about it” reply. From the article: > But it’s used at my job, so I’m sort of forced to have an opinion about it.
- ademup 5y agoIt seems like this should have been titled "My views on Rust" as overall, the negatives don't really outweigh the positives. Good job for making the front page of HN, but I honestly struggle to know why. (Maybe you're famous?)
- cjohansson 5y agoI think the "Negative" part is really what made the article get to the front page. Rust is popular so anything negative about it causes salience
- rapsey 5y agoIndeed this is a content free article. Why is it at the top of HN?
- jgilias 5y agoTLDR: - I see 'unsafe' everywhere; - Async is problematic, colored functions! - Community is nice, but it won't be forever, RIIR people are annoying; Conclusion: I prefer GCed languages with default async runtimes.
- Animats 5y agoI see too much "unsafe" in libraries, too. I write Rust code with no "unsafe", and it's hard. Sometimes you have to go back and do a major redesign because you painted yourself into a corner. Sometimes you take a performance hit. Some crates with "unsafe" that shouldn't have to have it: * priority-queue ("Improved performance using some unsafe code in the implementation.") * serde-json, uuid (takes in byte strings and makes UTF-8, without being strict enough about types.) * crossbeam-channel (lock-free code which does atomic operations on small structs by coercing them into numeric types for which atomic operations are supported.) There are a relatively small number of pain points which lead people into unsafe pure Rust. The language needs an effort to hammer them out. (I'm not talking about foreign function interfaces to legacy C/C++code; that's never going to be safe, but can become obsolete.) Async is problematic, colored functions! The web backend crowd wants to write Javascript-type code in Rust. This is a bad fit. As I've said before, web backend stuff with huge numbers of connections should be written in Go. Goroutines and garbage collection are a better fit to that problem, because there's only one thread-like construct and it's both low-overhead and preeemptable. The Rust approach complicates code that's changed frequently ("agile", right?). You have to be careful about what's async, what's a thread, what's non-threadable async, and what runs more than 100us without giving up control. Too much engineering is required for routine web server stuff. Go handles that all automatically. I'd like to see two hard problems addressed in the language: backpointers and lock order. You can do backpointers with strong reference counts forward and weak reference counts backwards, but now you're reference counting everywhere. If you screw up and mutably borrow twice, you get a run-time error when you call ".borrow_mut()". The borrow checker doesn't look at reference counted items. Single owner with backpointer ought to be analyzable statically, although it's hard to do. The basic constraint is that the call chain can't pass through the same mutably borrowed struct twice. That is, it's loop-free. There are additional issues about keeping forward and back pointers in sync, but those are easier than statically detecting a double borrow. Lock order is a closely related problem. You can't lock the same thing twice in the same thread. Again, this is a constraint that the call chain can't pass through the same lock twice. Also, locks must be ordered, so that you don't deadlock by locking A, then B in one thread, while locking B, then A in another. Again, a constraint on the call chain. Both of those are hard theoretical problems, and work is underway on addressing the first one, at least. Not having a sound solution to these problems leads to hack workarounds. There's other little stuff to gripe about, but those are the big items that lead either to serious bugs or major rework.
- roenxi 5y ago> The Rewrite Fallacy This is a good general point that isn't even about Rust. It crops up a lot in the always ongoing database wars where people keep swearing that one database is fast or slow or new or old. There needs to be without a thoughtful acknowledgement that there are design trade-offs involved and that appropriateness for the situation is more important than the raw technology. A rewrite making code fast always raises questions about why the rewrite was necessary, what battle-hardened error cases might have been lost along the way and whether the speed-up is attributable to the tech or the skill and intent of the programmer.
- mhaberl 5y ago> I predict that garbage collectors will become popular in Rust eventually. Not having a GC and not freeing memory by hand is one of the features that makes Rust special. What would be the point of this? > I feel like Rust is self-defined as a “systems” language, but it’s being used to write web apps and command-line tools and all sorts of things. This is a little disappointing Why would using the language for non-system programming be disappointing? I have a feeeling that it has become popular lately to criticize Rust for whatever reason, I guess that's what happens when more people use the language
- erk__ 5y agoA interesting paper I saw about adding a GC to Rust is this[0] where they made some programming challenges and showed that the ones who used a GC finished the task faster. [0]: https://arxiv.org/abs/2110.01098 https://arxiv.org/abs/2110.01098
- Xylakant 5y agoThe counterpoint is that using a GC makes the workload unpredictable. The GC may kick in at any time. Rust has a predictable performance profile and that’s important in some applications.
- alblue 5y agoNote that GC makes explicit the costs associated with memory allocation and freeing; languages that use manual memory management (or semi automated memory management as in Swift/Rust) simply un-amortise the cost and distribute it all over the program. While Rust may have less issues than other languages in this regard, it doesn’t change the fact that destruction of a “thing” can result in a transitive set of “other things” being destroyed as well, and depending on the state of the program, this set could have a pretty high bound. Even in a “predictable” language like Rust, a data entry containing a map like structure is going to have a different destruction time if the map is empty vs if it is full. The other aspect of “predictable” delays in a program completely ignores the runtime issues that can happen at the OS layer, such as swapping/page cache invalidations/migrations between cores of numa regions etc. so it is rarely the case that any program in any language is going to have predictable behaviour. Even trivial things, like the number/size of environment variables user at program startup can have a performance delta. Anyway, the point is that when programmers talk about “predictable” behaviour in a program, what they generally mean is “invisible performance problems” and so it gets swept under the carpet. That’s not to say that GC doesn’t introduce variance into measurements, but it is not the only thing that causes variance and many of the good GCs are capable of using multiple cores and can avoid interrupting the program runtime without significant overhead, although obviously tracing collectors will increase pressure on a memory system in a way that explicit/automatic memory management does not.
- nemothekid 5y ago>but it’s being used to write web apps and command-line tools and all sorts of things. Are people writing webapps in Rust? When I look at trending Rust projects and Github what I tend to see are databases and crypto.
- lewantmontreal 5y agoCommand line tools for sure, though. Is there any other language that offers something like structopt?
- cedws 5y agoHere's a story: I once did a hackathon with a few acquaintances for a few hours where our goal was to write a simple Matrix bot. Given that we were always chatting about Rust, a couple chose it for their bot. I chose Python. My basic bot was done in about an hour. One of the guys took about an hour to try and compile an outdated, abandoned crate for interacting with the Matrix API. I recall he then had to write his own using async/futures. It took him about 6 hours and he was working well into the early morning after we'd already left. The resulting code was hideous - a slurry of nested closures, ?s, unwrap()s everywhere. The compiler was throwing demonicly complex compile errors at him and he was doing whatever he could to get it just to compile. Bearing in mind he was not new to the language. No, I'm not arguing that Python is better, these languages clearly have a different purpose. I'm arguing that if it takes a really smart guy like him more than 6 hours to produce something of that quality in Rust then... it's not for me. I've already tried it and development with it is just slow and I don't like several syntax decisions. Not to mention the crate ecosystem which is primed to be the new npm disaster.
- smt88 5y agoOptimizing for the first 6 hours of development is insane and also the reason we have so many towering piles of unmaintainable garbage in our industry. Rust is the wrong language for a hackathon, but hackathons are an extreme edge case. Most devs work on large, aging code bases built by other people. Rust and similar languages make that work much less error-prone. Who cares if it's not good for a hackathon?
- cedws 5y agoWhat should the expectations be then? I don't think 6 hours is an unreasonable timeframe to produce a Matrix bot in any language (we're not counting esolangs of course). It's a POST request, I mean come on. Maybe a GET long poll as well. How long should it take in Rust?
- option_greek 5y agoIt takes a couple of lines to call any API in Rust using reqwest: https://github.com/seanmonstar/reqwest https://github.com/seanmonstar/reqwest I'm not sure where this 6 hours for matrix bot thingy comes from. A better comparison would be to write something from scratch or use comparable frameworks.
- hitekker 5y ago> This is a little disappointing, but also predictable: the more successful your language, the more people will use your language for things it wasn’t intended for. I thinks that one part of it. More worryingly, I’ve heard the Core Rust committee has a hard time saying “no” to new features which leads to bloat in the language.
- raverbashing 5y agoThis is a very good insight: > The worst kind of compile error is the one where the compiler is complaining about something that it generated for you, rather than something you explicitly wrote. > This can be compared with Haskell’s use of monads, that provide syntactic sugar. The more magic you introduce, the harder it is for newbies to learn and to talk about. I agree. Too much magic (or in the wrong places - especially when it's a crutch to some language quirk) makes things awful.
- grumpyprole 5y agoHaskell actually goes to a lot of trouble to type check before desugaring. So lots of sugar, e.g list comprehensions, do get nice type error messages.
- Subsentient 5y agoRust is a good language overall, but it has some serious flaws that it seems those in control of Rust have no interest in fixing. For example, it is possible to make the borrow checker accept self-referential structures, but nobody has done the immovable type etc work required for that. Which means, for non-trivial data structures, you need to either reach for unsafe or Rc/Arc. I write a lot of very multithreaded code, so for me it's almost always Arc, which means paying for atomics. And since the Drop trait takes an exclusive &mut reference, you must use fugly nested structs to prevent UB if you have shared mutable pointers you need deleted automatically. I'd recommend learning Rust, but I'd also strongly recommend that you willfully push the limits of the language. Rust needs to be stretched out to accommodate more contemporary programming constructs, and you can help with that. Also, stay away from the core team and organization, they're poisonous as hell. I'd recommend donating to gccrs to help alternate implementations. On the positive side, you do still end up with an awful lot of zero-cost safe code, and Rust is pretty nice to work in once you actually understand it.
- Lorkki 5y ago> Arc, which means paying for atomics As far as I understand, that should be practically zero-cost on x86, and quite cheap also on ARM - and it's also only paid during acquisition and destruction. I haven't yet caught refcounting in profiling as being the cause of unacceptable performance.
- Const-me 5y ago> that should be practically zero-cost on x86 It’s practically zero cost when uncontested. When contested, the instructions with that `lock` prefix are concurrently accessing a single cache line from multiple cores at the same time. These cache coherency protocols are relatively slow. On some processors, reading a cache line recently modified by another core can cost 300-500 cycles, way more expensive than a cache miss and roundtrip to off-chip memory.
- Lorkki 5y agoThat is also true. But as said, I haven't yet personally run into a case where refcounting was contested to a point of making it an optimisation priority.
- outsomnia 5y agoVery good point in there about the effect investment has on objectivity. Proponents conflate a specific approach for memory "correctness" checking with some judgment of what is "correct", or not if it doesn't fit in the checker model. I get a lot of juice out of a solid linked list abstraction in C, it has many benefits such as modest footprint leading to naturally extensible and composable object lists everywhere instead of fixed arrays that have to overallocate and break when it's not enough for some usecase. The lifecycle of the allocations that bind to the list can be opaque, but in it's not opaque to valgrind and leaks are visible without additional in-code instrumentation. If the valuable uses of that abstraction cannot be handled by the borrow checker, it just means that is a restriction imposed by that checker implementation, it is not telling us that this architecture is not "correct".
- DeathArrow 5y agoI feel Nim has the better approach towards memory management among new languages. You can pick between a few memory management schemes, use a garbage collector when needed, use manual memory management when needed or not have memory management at all if it suits your use case better.
- rendall 5y agoGiven some of the responses to this article, I'd like to note that the guidelines explicitly ask Please don't post shallow dismissals, especially of other people's work. Let us know what the article gets wrong. https://news.ycombinator.com/newsguidelines.html https://news.ycombinator.com/newsguidelines.html
- stackbutterflow 5y agoOn the other hand I think Rust is the future.I started using it for side projects and it's been nothing but a pleasurable experience. Any place to find Rust jobs for experienced dev but new to the language?
- stevepeg 5y agoSend me an email at jobs [at] dailyedit [dotcom] We're a Rust shop doing something interesting with NLP and web.
- rmanolis 5y agoRust does not bind well with C for this reason it can not become a system level programming https://way-cooler.org/blog/2019/04/29/rewriting-way-cooler-in-c.html https://way-cooler.org/blog/2019/04/29/rewriting-way-cooler-... However, there is another programming language that does not need bindings. It is called Zig and here it explains how it solves the same problem https://youtube.com/watch?v=mwrA5IRGpfU&feature=share https://youtube.com/watch?v=mwrA5IRGpfU&feature=share
- erk__ 5y agoBut that it does not bind well with the memory model of a certain wayland implementation does not mean that it cannot bind well with C generally. It also does not mean you cannot use it for Wayland since there is a native Wayland implementation. [0] And for the systems level programming there is stuff like the current work to make use of Rust and the guarantees it gives in large C based systems like the Linux kernel. That said that Zig is not a worthy endeavour, it does just not give as strong guarantees about memory safety as Rust works to give. (at least if this article is up to date [1]) [0]: https://github.com/Smithay/smithay https://github.com/Smithay/smithay [1]: https://www.scattered-thoughts.net/writing/how-safe-is-zig/ https://www.scattered-thoughts.net/writing/how-safe-is-zig/
- coldtea 5y agoI'd like to see a Rust without Rust's main proposition (and main hurdle). That is, a language that has most of the surface syntax and semantics of Rust, except anything related to the borrow checker - instead, it's all handled by a runtime GC. So there is pattern matches, immutability, traits, and so on, in Rust style, but no lifetimes and related syntax. Let's call it WD-40. Bonus points if this WD-40 language can also trivially call regular Rust libraries. P.S. After I've written this, I read the rest of the comments, and half of them are about the same kind of idea...
- Const-me 5y ago> So there is pattern matches, immutability, traits, and so on, in Rust style, but no lifetimes and related syntax. I think C# fits the bill. Pattern matching: https://docs.microsoft.com/en-us/dotnet/csharp/fundamentals/functional/pattern-matching https://docs.microsoft.com/en-us/dotnet/csharp/fundamentals/... Immutability arrived recently: https://nietras.com/2021/06/14/csharp-10-record-struct/ https://nietras.com/2021/06/14/csharp-10-record-struct/ Traits are different however. The language has interfaces for decades, when used as generic constraints they’re free performance wise i.e. don’t compile into virtual calls (also allows to use interfaces on value types without boxing things into the heap), however it’s impossible to implement traits externally like `impl Interface for Type` in Rust.
- grumpyprole 5y agoF# would fit the bill better I think compared to C#. F# has proper algebraic types like Rust, full pattern matching, immutability by default, less OOP baggage.
- Const-me 5y agoI don’t disagree, but some other stuff often used in system and low-level programming is easier to use from C#: stackalloc and unmanaged heap, spans, SIMD intrinsics from System.Runtime.Intrinsics namespace, scalar intrinsics from BinaryPrimitives and BitOperations classes, C interop, threads synchronization, etc.
- jph 5y ago> it’s being used to write web apps and command-line tools and all sorts of things. Yes because crates are great IMHO. Warp for low-level web apps with filters is flexible. Rocket for high-level web apps has batteries included. CLAP for command line argument parsing is easy. Serde is superb for serialization/deserialization. Diesel and sqlx make data access efficient. Is there a learning curve? Yes for sure. It can be hard for new teammates coming from JavaScript/Python/Ruby to learn about Box, Arc, Rc, From/Into, etc. The borrow checker is like a pro coach-- when you work with it, then it makes the coding process much better.
- JBits 5y agoA question for devs experienced with asynchronous/concurrent programming: what's your take on coloured vs non-coloured functions (ie., stackless vs stackfull coroutines)?
- kangalioo 5y agoSome of those are good points. But the author mentioned multiple times how Rust should have a GC, which makes me think they're missing the point of the language: a systems language as fast as C++ and with no runtime