Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
My negative views on Rust (chrisdone.com)
52 points by nikivi on Dec 23, 2021 | hide | past | favorite | 89 comments


Here'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.


Optimizing 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?


What 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?


It takes a couple of lines to call any API in Rust using 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.


It's not just where. It's when. I suspect it's true but like a few years ago (I haven't really monitored Rust due to real life work).


I don’t think it’s just 6 hours. Rust requires more up-front design both during initial development and when doing maintenance compared to Python. One has to specify things in much more detail when writing Rust and sometimes that’s great, but other times it doesn’t really matter much. Many times one doesn’t really care about the overhead of GC or that values a copied a lot.

I’ve always written default-efficient code myself (mostly in C++) and using Python exclusively and over a longer time period for data wrangling was an educational experience. It feels quite liberating to just write code without having to think at every point about efficiency and memory.


What I got from your anecdata is this:

- Rust isn't good at writing scripts (one-off code)

- 30 year old language with massive popularity has better libraries than a relatively unknown 6 year old one.

- Rust async isn't mature enough.


Every language has its appropriate uses. Maybe this isn't where Rust shines.

Do you need type safety or static type checking? Are you dealing with concurrency, or need the performance that manually managing memory provides? Do you want safety when doing low-level operations such that the compiler can eliminate many classes of mistakes?

Rust might be the right choice.

Are you trying to write a throwaway chat bot for hackathon and you only have a few hours?

Rust probably isn't the right choice unless you're very, very skilled.


I find Nim performant enough while having a GC. Also type checking. And the productivity is on par with Python, easily.


That's the only kind of context I think I'd use Rust in personally - embedded, bare metal, low level stuff. Certainly not for userspace or web applications. But a lot of projects are using it anyway even if something simpler and more mature will suffice.


now let's imagine this matrix bot becomes a product, running on thousands of servers.

the python version is 100x less energy efficient than the rust version. that 5 hours extra work now becomes a bargain.


> now let's imagine this matrix bot becomes a product, running on thousands of servers. the python version is 100x less energy efficient than the rust version. that 5 hours extra work now becomes a bargain.

Not necessarily. If the limiting factor is network access, then the language you write in wouldn't make any difference. You could say you would use less ram with the rust version, but ram is cheap compared to developer time.


Not so sure about that. JITs can be fast, faster than C or Rust in some circumstances. Besides, the code was a trainwreck.


Show me any real benchmarks where actual python is faster or just as fast as C or Rust please. The python GIL shines with it's presence, it will not be as fast in any real workload and we're usually fine with that because speed doesn't usually matter that much when we're waiting on I/O all the time anyways.


The code was a trainwreck because it was written with the aim of getting it done in a handful of hours and without using a properly designed Matrix crate. For a real world use case, you'd just use matrix-rust-sdk.


> faster than C or Rust in some circumstances

how?


I remember asking the same question about Java many years ago.

Some optimizations become much easier in the actual running environment. You know the hardware so don't have to cater to lowest common denominator, and you know what's actually happening and don't have to guess.

Profile-guided optimizations later showed up to bridge some of the gap, but I think JITs are typically built with a different mind set, so there are some things they excel at.

A funny example is something like a regexp matcher where a JIT might take an actual regexp built on the fly, say based on a user searching for "foo bar", and optimize code for it.


Dynamic optimizations for the specific target machine and also long lifetimes. For example when a specific target machine has a specific CPU instruction that the JIT can leverage, or has a ton of RAM that the JIT can use for caching such as for memoized methods.


for some JITs. Java's vm approaches or exceeds C in terms of speed. Unless something has changed, Python's runtime is very slow compared to just about everything else.


"Premature optimization is the root of all evil." --Ken Thompson

"You Ain't Gonna Need It." --Martin Fowler

I'm not saying don't do it -- in some cases it makes sense say as an open source project. But you can get away with a lot of python code before you have to break out the compiled languages -- particularly if the IO cost is significantly more time consuming than your business logic.


> "Premature optimization is the root of all evil." --Ken Thompson

Actually, the quote is by Donald Knuth [0].

[0] https://wiki.c2.com/?PrematureOptimization


Thanks for the clarification.


Building V1 in a rapid development language and porting to a performant language when scale becomes an issue is a pretty popular pattern.

Personally, I wouldn’t prototype in Rust either, but OTOH I’m not experienced enough in it.


> Building V1 in a rapid development language and porting to a performant language when scale becomes an issue is a pretty popular pattern.

I'd say building V1 in a rapid development language and then never porting it while trying to scale it up is an even more popular pattern.

There are some massive web applications out there running on hopelessly outdated Django


> 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


“There are only two kinds of programming languages: those people always complain about, and those nobody uses.”


Thats a keeper :) Does this quote have a history?


It’s from Bjarne Stroustrup regarding people hating on c++


A 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


> a randomized controlled trial with volunteers from a 633-person class, collecting data from 428 students in total

If I understand this experiment, college students i.e. in average completely inexperienced programmers, where tested. IMHO, this only points to the fact that Rust has a steep learning curve. I can imagine that using javascript instead of Rust would have them finish their tasks even faster, but doesn't tell us that GC in Rust is a great idea.


What aspect is steep?

From the code I've seen, Rust is intuitive when coming from the classical languages like Java, C or JS. It's not lisp or Haskell.

To clarify, I don't intend to come off dismissive. I'm genuinely curious what the scary parts are so I can better plan my own studies.


The borrow checker and lifetimes have been my pain points. Also understanding Some and Result, which after practicing I understood them, and now they are ok. They were foreign concepts to me.

I still struggle with lifetimes, but I do understand them better.


I personnaly find the ownership thing really hard to get. That's the thing that protexts you from screwing memory in parallel code but the thing is you have to use it even in non parallel code. The other thing is that it's a set of rule which mixes with the type system, so at the beginning, I had hard times understanding if I had issues with my types or with the ownership (eventhough, I know, ownership issues are reported as such by the compiler). So in the end, you have to think about memory safety much more deeply. I get that my code really feels right once it's written with ownership principles but somehow, it makes Rust hard to start with. Now, this ownership part is something really new to me (I have ASM,C++,Python,Java real life experience), it makes me think better about about my programs. So it's a tough but fruitful experience.


The most common issues are with ownership, lifetimes, and the borrow checker.

If the person is an experienced C or C++ programmer they'll probably have an easier time as you need some understanding of ownership and lifetimes to correctly use pointer-likes in those languages. The most likely issue here is that their mental model of ownership and lifetimes does not exactly match the borrow checker's.

If they're coming from a language such as C# or Python, where you don't need to deal with these to anywhere near the same extent, suddenly being forced to reason about it just to pass the compiler can be bit of a hurdle.


Would be interesting to see this repeated with people that had significant Rust experience rather than a class of students mostly coming to the language for the first time.


The interesting part is putting a number to this: 4 vs 12 hours. Just the direction of the inequality is of course unsurprising.

I have looked superficially at Rust since I have no use case for me right now and it's truly complex but people downplay the importance of not having GC. There are plenty of languages with GC, for a reason. People use C, C++ or similar for a reason too, not out of masochism.


this study is extremely flawed. It is impossible to tell if these results are from the garbage collection or how bronze violates rust aliasing


The 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.


Note 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.


> Note 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

This is generally an interesting feature of garbage collected languages, and it's often more efficient than manual memory management - but it does come with downsides.

> 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.

"Predictable" does not mean "always the same". It means that given a map with the same size and fill level, destroying it will take the same time. What's more important is that the point in the program where the destruction happens can be controlled - and, if necessary, moved out of the critical path of something that requires response within a certain bound. This may introduces an overall inefficiency in the program, but if you have software that needs to fulfill certain time bounds, that's the tradeoff you choose. Doing so in a garbage collected language is much harder.

And rust targets environments where (near)-realtime behavior and predictable performance is important, or where garbage collection is not truly possible since allocation isn't even possible (think embedded systems).

> 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.

I don't see how this is a counterpoint to what I said - programmers blaming other things for performance problem has been a thing like forever.


>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?

To put it bluntly: to make writing Rust fast and fun. If you think it's fast and fun right now, you're either very good at it or somehow delusional.


Agree with this. I wrote some non-trivial amount of code in Rust just to give is a proper try. After countless hours spent in understanding borrow checker, life times and waiting for compilation to finish, I still have to constantly fight borrow checker. When working with Rust, I am not "making thing X" but instead "writing Rust which happens to be X". The code is littered with either `unwrap` of `?` which is just exception management done manually with hardly any benefit.

On systems programming front, last time I checked there were two options to make system calls (apart from writing inline assembly), the `libc` or the `nix` crate. `libc` is just a wrapper so exposes `unsafe` C like API which doesn't make for idiomatic Rust code. `nix` was incomplete on lots of front, not sure if things have changed now since it has been a while I tried Rust. So much for a systems programming language.


What is wrong with `?`? I consider Option<T> as a plus. Unwrap is hack but '?' is good error handling. Better then littered code with unnecessary ifs (which you need to use even in GC languages).


Honestly, if you're working within a well-architected framework, writing Rust is genuinely a joy (except perhaps async). The painful challenges of "how do I design something that plays nice with the borrow checker" can be solved once, and then you just stick to convention and enjoy the expressiveness of the trait system.


Is GC for Rust possible in the future? I’d love that if it means simpler compiler error messages for e.g. closures.


What would garbage collection buy you in a language like Rust?


>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?

That some people don't care what makes a language "special", but e.g. like its syntax, ergonomics, ecosystem, and so on.


Rust 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.


> 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.


> 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.


That 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.


I think one the main use-cases for RCU in kernel is to alleviate the need for atomic reference counting in places where it would significantly impact performance. What you are saying might be indicative of one of the points that author raised: People mostly use Rust in non-system contexts where they don't really care that much about performance and would be better served by GC-ed language with runtime.


I'm not sure what counts as a non-system context these days. Most of my experience with using Rust in production was with a message queue type of service, where the desire was to minimize latency and to have consistent performance over prolonged use. I did make an initial prototype with C#, but things were much easier to make work well on both counts with Rust and Tokio.


> a message queue type of service, where the desire was to minimize latency and to have consistent performance over prolonged use.

Your requirements are probably similar to this C# queues class: https://github.com/Const-me/Vrmac/blob/master/VrmacVideo/Aud... That library decodes and plays realtime video + audio, both low latency and consistent performance over prolonged use were rather important. BTW that code runs on Raspberry Pi4, CPU performance is a fraction of what you’d expect on modern desktops or servers.


> 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.


Rust 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-... 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


But 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

[1]: https://www.scattered-thoughts.net/writing/how-safe-is-zig/


> 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.


Very 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".


Some 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


It 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?)


I 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


Indeed this is a content free article. Why is it at the top of HN?


>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.


Command line tools for sure, though. Is there any other language that offers something like structopt?


I'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...


> 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/... Immutability arrived recently: 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.


F# 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.


I 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.


Sadly even in its latest incarnation it doesn’t. It still doesn’t have basic exhaustive pattern matching/sum types. More importantly, even once it gets that, its standard library wasn’t written with them in mind. It gained (value) tuples quite late, so standard library functions still use awkward “out” parameters and so on.


>I think C# fits the bill.

It should also have the other Rust aspects: LLVM binaries, no MS involved, and so on.


> LLVM binaries

I wouldn’t want LLVM, I like JIT. The binaries are CPU and OS agnostic; sometimes I debug C# code on AMD64 Win10 which then runs on Alpine Linux with ARMv7 and ARM64 CPU. It’s relatively easy to generate code in runtime, allows to beat C performance in some cases, and enables good serialization libraries. Binaries are tiny because CIL is more efficient than machine code.

In modern .NET startup time is pretty good despite the JIT. Also, on modern hardware you wouldn’t want short-lived processes being launching at kilohertz frequency regardless on the language. Because cache hierarchy, you’d want to reuse RAM pages over time as much as possible.

> no MS involved

I think after the complete thing is cross platform and open source, MS involvement is not a huge deal anymore.


I guess you could DSL this on top of Nim-lang...


What's missing in D-lang for it to be this language?


That it would be better to hijack on an increasingly popular language and ecosystem like Rust.


In that case, the solution would be to make D-lang more popular, IMO.


On 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?


Send me an email at jobs [at] dailyedit [dotcom]

We're a Rust shop doing something interesting with NLP and web.


This 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.


Haskell 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.


Given 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


> 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.


A question for devs experienced with asynchronous/concurrent programming: what's your take on coloured vs non-coloured functions (ie., stackless vs stackfull coroutines)?


I 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.


TLDR:

- 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.


I 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.


Your points are much more meaningful than what's expressed in the article.

Regarding unsafe though. In other non-GC languages (C/C++, say) there's no keyword for `unsafe` as that is the default state. And that's fine. People generally don't have too much trouble trusting library authors to mostly do the right thing. In Rust the places where you have to defer to human judgement are clearly marked, and I see that as a net benefit over status quo irrespective of how much `unsafe` is actually used in one or another library.

GC-ed languages are a different matter altogether. They sit on a different point in the trade-offs graph in my opinion. However, pointing out that the design trade-offs that have been taken in Rust may not be ideal for one or another use case is very much a valid thing to say!


Another '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.


> 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.




Consider applying for YC's Summer 2026 batch! Applications are open till May 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: