I am not convinced about that. I think that many people discovered the notion of "memory safety" with Rust, and think that only Rust provides it. The grandparent is right: Rust brings memory safety at low cost, that's the whole point.
I am not a Rust fan by any mean, but it feels like this rant is not completely informed. Things like:
> Just give me a garbage collector, and let me do what I want to do!
and
> But when compared with other languages (like Go), its “safety” to me is more of a detriment.
Sound like the author is not exactly clear about what "memory safety" is. Many languages are memory safe. The difference is that Rust aims for memory safety at zero (in practice "very low") cost. If garbage collected languages could do that without sacrificing their simplicity, they would do it.
It's a tradeoff. If Kotlin is fine for you in terms of performances, then use it! Rust is rather an alternative for C/C++, where performance matters. Feel free to use Rust wherever you want if you love it, but don't use it when performance does not matter if you hate it!
The problem is Rust's marketing. They sell the language too well for use cases that don't need the same degree of safety or speed, and Java (or Go, or C#) would be the more pragmatic choice.
If you find yourself writing an OS or browser, Rust is a great choice. Basically anything where C++ is the alternative.
100%. My fear is that the backlash spreads the way the hype did (about rust being best for everything) did, and suddenly rust is the choice for nothing. My experiences are very positive, but I work mostly in the narrow-ish cases that Rust is designed for, in C, C++, systems areas.
> My deepest fear is that the backlash spreads the way the hype did (about rust being best for everything) did, and suddenly rust is the choice for nothing.
I could totally imagine its popularity going down in places where garbage-collected languages are fine, but... don't you think it has a future in those places where C/C++ are needed (e.g. systems areas, as you mentioned).
For Rust to lose everywhere would require C++ to win against Rust. Not sure if that's possible.
I think the dip will be deeper than people anticipate. Back to very niche cases. The fact that Linux & Windows is pulling more and more Rust (albeit cautiously), I think secures its future as a C/C++ augmentation for systemsy stuff.
The big C/C++ domains haven't really adopted it like I'd hope they would before that dip: Automotive, Aerospace, Robotics, Desktop, Embedded. It's quite perfect for some of those, but they're fighting incumbents without an eccosystem to back them so that will take a long time. It's not like rewriting sudo or ls, you have to rewrite everything to move from a C RTOS to something like a Rust embedded HAL.
I know more people who currently build things with Ada than I know people who currently build thing with C (professionally, because almost every Ada dev I know have at least an arduino).
Probably that says more about the people I know than about the language if I'm honest.
Yeah, unfortunately the world is super into c and c++ tot he point that billions have been spent on making it safe via frama-c, astree and friends rather than in funding an actual safe language.
Straight up program correctness is drastically improved thanks to sum types, enumeration, and other features of Rust.
These do come with some upfront cost. Having used Rust for years, I think these costs tend to be overblown. They disproportionately impact newcomers (which in and of itself is a problem!) and particularly those who don’t care about learning to write new languages idiomatically. Still, though, it’s usually at least a little slower to go from zero to fully functional.
However in my experience Rust programs require far less ongoing maintenance which is where the vast majority of time in software is spent. New features tend to be added more easily and entire categories of bugs (more than just memory safety) are completely prevented by the type system. Even large refactors are usually relatively easy and once it compiles, it probably passes the tests too.
In some cases every additional day you’re late to launch is disastrous. But when it’s not, the time savings you get from not chasing down runtime errors, nil dereferences, unhandled exceptions, issues stemming from new and partially-handled enum variants, etc. end up recouping the upfront costs tenfold.
The upfront costs do make Rust less competitive in areas that have quickly-changing requirements. And that’s totally reasonable, no language is perfect at everything. But the further you get away from sales-driven users and the closer you get toward slower-moving core infrastructure, the more the reduced maintenance costs start paying off.
Exactly. So was Go in it's time. Their marketing sounded like everyone else did garbage collection wrong, and that their approach is best for all use cases and niches.
I have a vague hunch where Rust is chosen because of the good quality abstraction the language support that's missing from modern languages.
I keep joking about it, but immutability is si valuable for general software development. None of the mainstream languages support that, but Rust achieves the same benefits (even if in a different way). Then the Rust type system is sound while modern languages are still dealing with problematic nulls and lack of advanced types (like what's possible with typescript)
Between endless builder patterns and the let if/match syntax it does get quite wide and ugly relative to C or something. But it definitely has its upsides.
I programmed in C++ before, mostly doing high performance stuff. Like anyone who used C++ for a while, I had issues with the language. Here are why I dislike it:
1. Compile times. There's a big difference in user experience between <10sec and >30 sec between clicking "build" and getting feedback on what mistakes you made.
Above 15-20 seconds I tend to shift my focus to something else. This means when I read the error message I have to context switch back to the task. The productivity gains from fast builds (Go, D, or even Python to be honest) are immense in my experience.
2. The syntax is bad. It's rare to have a meaningful line of code with fewer than 70-90 characters. Your eyes go horizontally as well as vertically. There's a lot of coginitive overhead in learning which stuff to skip reading, because it's boilerplate or language quirks.
3. Building C++ is nonsense, everyone has their own different solution, so getting external libraries into a project that aren't header only is hell. And header only libraries make problem #1 even worse.
C++ being insecure is not my problem. Rust focuses hard on that thing which is not my problem, but Rust puts little focus on problems #1 and #2. They do solve problem #3, they have a package manager, great, but every other language also does that so it's not a competitive advantage for me.
I seriously doubt if most people listed their priorities with languages they would align with Rust's. Few people are actually writing linux kernel code or core system libraries that could expose dangerous memory bugs.
Re #1, when writing Rust consider using cargo check instead of cargo build. It stops a few stages before code gen so it can give you feedback faster. It doesn't help when you want to run your runtime tests, but will speed up the cycle of getting code that can compile in the first place.
I think this omits one item that can be relevant. It talks about rust being fast. Rust can be quite slow to compile. If development velocity is relevant, then Rust may not be as "fast" as go to compile as an example. Of course, some folks are chasing speed at all costs (and spending 18 months re-writing to do so). Rust may be a good fit there.
Yeah I think he's just coming from a totally different operating domain. I cannot even imagine going from Typescript to C/C++/Rust. I'm even impressed OP maybe it this far...
Same, and then they provide a Go example that… is basically identical? Then they complain about Rust not providing stack information about errors, but at the same time the Go equivalent just does `return nil, err` everywhere, also throwing away stack traces.
They correctly point out that you can wrap errors in Go with `errors.Wrap(...)`. But you can also do exactly the same thing in Rust with something like `std::backtrace`, the `failure`, or the `anyhow` crate.
There has been some uh, lively discussion about this post on various reddits since yesterday.
The author said
> I wanted to try writing the article in an inflammatory style for engagement.
but to respond to some of the things claimed, for anyone curious:
> Just give me a garbage collector, and let me do what I want to do!
This is absolutely a reasonable opinion to have, but it means Rust was just not the correct choice. That doesn't mean Rust is bad.
> Maybe I’m just an idiot and can’t figure out how to enable stack traces. But when an error happens in my application, I have no idea why!
Panics have an environment variable you can set to print a stacktrace. You can also grab a stacktrace yourself with the tools in std::backtrace, and many error libraries like anyhow will let you capture backtraces for Results. However, part of the pain the author is feeling here is that instead of using error objects directly, their example code shows them converting them to strings and then returning them that way. This is going to make figuring things out harder, but that's because you're not using the tools given.
Yes but the language is making it hard to use the tools given. It's easy enough to say it's a skill issue, and say they should have discovered RUST_BACKTRACE=1, but when you're learning the language and trying figure out how to use error objects in the first place the tools given don't work and just give me a string that says I'm doing a dumb shouldn't be so hard.
I would say that this has good discoverability. If you're learning the language and writing your algorithmic trading platform in it, The Book should probably be the first document that you go to.
When encountering panics, the runtime output will tell you how to get the backtrace:
thread 'main' panicked at src/main.rs:3:7:
called `Option::unwrap()` on a `None` value
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
It's true that neither rustc nor clippy complain about having a `Result<_, String>` return type. Maybe they should. It wouldn't be too hard to implement such a lint, but I would expect people to be annoyed by it.
I would argue that in 18 months there are plenty of chances to come across any of the documentation and blog posts that explain this, or to ask questions in https://users.rust-lang.org.
I want our toolchain to be as easy to use as possible, to make it best in class. I have a long list of things I'd like to see improve in Rust. The critiques in the article are not constructive, neither in presentation nor substance.
> It's true that neither rustc nor clippy complain about having a `Result<_, String>` return type.
I would love to understand where the original author picked up that unfortunate idea from. I’ve never seen someone do this, and it’s very explicitly throwing away all additional error information by converting it to strings. No wonder you can’t figure out where your errors are coming from!
If I would take a guess about a total stranger, it appears that they are a printf debugger. No shade, I am too. But it's not a huge leap to go "the thing I do with errors is print them to the screen, and you print strings to the screen, so strings make sense as error conditions."
Furthermore, they seem to enjoy Go, and Go's version of Rust's Error trait provides one method, Error, which returns a string. While I haven't written meaningful Go, and can't speak to its idioms (though as far as I understand, "just turn it into a string" is not idiomatic Go), it's another sign pointing towards "the easiest way to handle errors is to just turn 'em into strings", especially if you're just trying to ship something and don't care about the details.
> (though as far as I understand, "just turn it into a string" is not idiomatic Go)
Sadly while I’ve seen many argue that it’s not idiomatic go, I’ve yet to see more than a handful of projects in the wild that don’t simply `return nil, err` because anything more than that is excruciating given the number of those lines in any given project.
I can't cite my sources, but I recently started learning Rust and I've been doing this. I would guess that I picked it up from the Rust book, since that's been my primary learning source.
I know I _could_ define my own error type, but that's tedious, especially if there are many types of errors to handle. For my (non-production) purposes it's been fine.
What's the idiomatic way to handle errors? Is there a way to collect more detailed error information without excessive boilerplate?
A common but of advice is “use anyhow for applications and thiserror for libraries” but what it really boils down to is, anyhow is good for handling errors, and thiserror is good for defining your own error types.
I'll be blunt, the Rust community is not known for being a warm fuzzy place to go ask stupid questions and walk away not feeling like a dumb fuck. Hoping people will wander into the right place to ask rust questions is a non-starter.
You don't control Stack Overflow or Reddit, or any number of slack/discords, so I don't know how I'd address that problem, but it's true.
Reddit is also moderated, but the cultural issues of that whole site, as well as those of StackOverflow, are well known by now.
I do my best to set a tone and lead by example whenever possible. Most of the times I've seen threads turn sour, it is usually catalyzed by people being unwilling to listen and acting hot heatedly to begin with. I've seen r/rust discussions where the article being discussed was far more critical of the language/toolchain than this one, but with far more constructive communication style and substantive analysis. The quality of the conversation in those cases have been much better.
Feel free to point me towards toxic community behavior and I'll do my best to address it through every mean available to me. I can't promise that there will be dramatic changes, but I certainly do my best to call out bad behavior and try to foster a space I can be proud to belong to. Then again, I do not spend much time in any of the sites you mention, so I can easily be missing bad behavior.
I would also say that even if you don't want to interact with people (for any reason), that's not an excuse to not seek out official or unofficial documentation. There is a non-comprehensive list at https://www.rust-lang.org/learn.
The OP had resources available to learn how to deal with errors in a more idiomatic way than he did:
I agree that just saying "skill issue" isn't the best, but also, it's totally fine to ask for help rather than write a blog post that says "This is a flawed language design."
I agree with you, the author should take an L for on that. Trying to handle errors the right way is an exercise in frustration for printf debugging. it's solved by using a debugger but sometimes that's not available, and passing Result<Option <String>,Box<dyn Error>> or whatever around in exactly the right way to error handle is just difficult. I figured it out eventually, but compared to, say, Python there was a steep learning curve. Some people will be able to scale it, others won't. Personally I think that's okay, not everything has to be python easy. Gatekeeping doesn't have to be bad. the real ass awkward reality is that not everyone has that type of reasoning skills to actually get it, and gatekeeping people out because they don't and can't get it doesn't have to be a bad thing. We shouldn't be surprised when someone complains about that though.
I do think that one unfortunate side effect of "the Project doesn't pick winners" is that it would certainly help newcomers to just know that anyhow exists. It could make those initial steps easier.
> Just give me a garbage collector, and let me do what I want to do!
Yes - a clear sign you have not found a good application for safety, security, and low-level control vs developer speed. Systems, safety critical, embedded, etc.
Why it expanded beyond this is not clear to me, other than hype and falling into a gaping void in distributed systems development that Go never filled for some reason.
> If we compare it to C++, it’s obviously the better language.
It really depends on what is meant by "better." The thing I like about C++ is its problems are well-known as is how to work around them. The thing that concerns me about Rust is we don't know all its problems - in practice. We will eventually, sure.
Sometimes I don't think we pay enough attention to how much our collective experience with a language matters.
It's not the case that we don't have work arounds, we simply don't have generally accepted and agreed-upon work arounds. You have options. For example, there's no generally accepted work around in C++ for manual memory management. You can develop your own strategy, but you may not be able to use libraries out of the box without having to create shims (or monads) but the point is: we know how to do these things. Most of the code in production has done these things and few people are interested in refactoring this huge investment to Rust.
I'm curious as to the lifetime annotations. This is essentially the language designer's intent to say "place a marker on this data field such that the compiler can trace the usage of the field to insure it is not accessed (before,after) the memory is released."
Therefore, the lifetime is expressed via an additional abstraction requiring the associated language syntax, compiler design, additional rulesets, etc.
Why would the same concept not be expressible as it's own data type, that would then be passed as data? In this case, you remove the additional abstraction. It seems like Jai is going that route, where you pass an arena type instance around and interact with it.
I do not understand taking so long to arrive at these conclusions. Each of them smacks you in the face pretty quickly if they bother you, so it's strange to invest so much time before deciding they are rant-worthy.
59 comments
[ 0.23 ms ] story [ 132 ms ] threadThis seems to be a severe misunderstanding, basically all typed pure functional languages are more safe: haskell, sml, ocaml, etc.
It is safe without a garbage collector that is the core benefit.
> Just give me a garbage collector, and let me do what I want to do!
and
> But when compared with other languages (like Go), its “safety” to me is more of a detriment.
Sound like the author is not exactly clear about what "memory safety" is. Many languages are memory safe. The difference is that Rust aims for memory safety at zero (in practice "very low") cost. If garbage collected languages could do that without sacrificing their simplicity, they would do it.
It's a tradeoff. If Kotlin is fine for you in terms of performances, then use it! Rust is rather an alternative for C/C++, where performance matters. Feel free to use Rust wherever you want if you love it, but don't use it when performance does not matter if you hate it!
> Just give me a garbage collector, and let me do what I want to do!
That line pretty much perfectly shows the author doesn't know what he's talking about.
Note to the author: Rust is specifically made for situations where you can't use a garbage collector.
If you find yourself writing an OS or browser, Rust is a great choice. Basically anything where C++ is the alternative.
I could totally imagine its popularity going down in places where garbage-collected languages are fine, but... don't you think it has a future in those places where C/C++ are needed (e.g. systems areas, as you mentioned).
For Rust to lose everywhere would require C++ to win against Rust. Not sure if that's possible.
The big C/C++ domains haven't really adopted it like I'd hope they would before that dip: Automotive, Aerospace, Robotics, Desktop, Embedded. It's quite perfect for some of those, but they're fighting incumbents without an eccosystem to back them so that will take a long time. It's not like rewriting sudo or ls, you have to rewrite everything to move from a C RTOS to something like a Rust embedded HAL.
I've always wondered why Ada didn't get more interest.
Probably that says more about the people I know than about the language if I'm honest.
Straight up program correctness is drastically improved thanks to sum types, enumeration, and other features of Rust.
These do come with some upfront cost. Having used Rust for years, I think these costs tend to be overblown. They disproportionately impact newcomers (which in and of itself is a problem!) and particularly those who don’t care about learning to write new languages idiomatically. Still, though, it’s usually at least a little slower to go from zero to fully functional.
However in my experience Rust programs require far less ongoing maintenance which is where the vast majority of time in software is spent. New features tend to be added more easily and entire categories of bugs (more than just memory safety) are completely prevented by the type system. Even large refactors are usually relatively easy and once it compiles, it probably passes the tests too.
In some cases every additional day you’re late to launch is disastrous. But when it’s not, the time savings you get from not chasing down runtime errors, nil dereferences, unhandled exceptions, issues stemming from new and partially-handled enum variants, etc. end up recouping the upfront costs tenfold.
The upfront costs do make Rust less competitive in areas that have quickly-changing requirements. And that’s totally reasonable, no language is perfect at everything. But the further you get away from sales-driven users and the closer you get toward slower-moving core infrastructure, the more the reduced maintenance costs start paying off.
Or a new C-like language, like Zig.
1. Compile times. There's a big difference in user experience between <10sec and >30 sec between clicking "build" and getting feedback on what mistakes you made.
Above 15-20 seconds I tend to shift my focus to something else. This means when I read the error message I have to context switch back to the task. The productivity gains from fast builds (Go, D, or even Python to be honest) are immense in my experience.
2. The syntax is bad. It's rare to have a meaningful line of code with fewer than 70-90 characters. Your eyes go horizontally as well as vertically. There's a lot of coginitive overhead in learning which stuff to skip reading, because it's boilerplate or language quirks.
3. Building C++ is nonsense, everyone has their own different solution, so getting external libraries into a project that aren't header only is hell. And header only libraries make problem #1 even worse.
C++ being insecure is not my problem. Rust focuses hard on that thing which is not my problem, but Rust puts little focus on problems #1 and #2. They do solve problem #3, they have a package manager, great, but every other language also does that so it's not a competitive advantage for me.
I seriously doubt if most people listed their priorities with languages they would align with Rust's. Few people are actually writing linux kernel code or core system libraries that could expose dangerous memory bugs.
Only thing I can think of like this is the "Your Programming Language Sucks" threads that are more meant as humorous hyperbole.
I meant, he is comparing that to pythons and typescript?
They correctly point out that you can wrap errors in Go with `errors.Wrap(...)`. But you can also do exactly the same thing in Rust with something like `std::backtrace`, the `failure`, or the `anyhow` crate.
edit: Cunningham's law :)
https://internals.rust-lang.org
https://rust-lang.zulipchat.com
The author said
> I wanted to try writing the article in an inflammatory style for engagement.
but to respond to some of the things claimed, for anyone curious:
> Just give me a garbage collector, and let me do what I want to do!
This is absolutely a reasonable opinion to have, but it means Rust was just not the correct choice. That doesn't mean Rust is bad.
> Maybe I’m just an idiot and can’t figure out how to enable stack traces. But when an error happens in my application, I have no idea why!
Panics have an environment variable you can set to print a stacktrace. You can also grab a stacktrace yourself with the tools in std::backtrace, and many error libraries like anyhow will let you capture backtraces for Results. However, part of the pain the author is feeling here is that instead of using error objects directly, their example code shows them converting them to strings and then returning them that way. This is going to make figuring things out harder, but that's because you're not using the tools given.
https://doc.rust-lang.org/book/ch09-01-unrecoverable-errors-...
I would say that this has good discoverability. If you're learning the language and writing your algorithmic trading platform in it, The Book should probably be the first document that you go to.
I would argue that in 18 months there are plenty of chances to come across any of the documentation and blog posts that explain this, or to ask questions in https://users.rust-lang.org.
I want our toolchain to be as easy to use as possible, to make it best in class. I have a long list of things I'd like to see improve in Rust. The critiques in the article are not constructive, neither in presentation nor substance.
I would love to understand where the original author picked up that unfortunate idea from. I’ve never seen someone do this, and it’s very explicitly throwing away all additional error information by converting it to strings. No wonder you can’t figure out where your errors are coming from!
Furthermore, they seem to enjoy Go, and Go's version of Rust's Error trait provides one method, Error, which returns a string. While I haven't written meaningful Go, and can't speak to its idioms (though as far as I understand, "just turn it into a string" is not idiomatic Go), it's another sign pointing towards "the easiest way to handle errors is to just turn 'em into strings", especially if you're just trying to ship something and don't care about the details.
Sadly while I’ve seen many argue that it’s not idiomatic go, I’ve yet to see more than a handful of projects in the wild that don’t simply `return nil, err` because anything more than that is excruciating given the number of those lines in any given project.
I know I _could_ define my own error type, but that's tedious, especially if there are many types of errors to handle. For my (non-production) purposes it's been fine.
What's the idiomatic way to handle errors? Is there a way to collect more detailed error information without excessive boilerplate?
The docs have good examples of basic usage: https://docs.rs/anyhow/latest/anyhow/
You don't control Stack Overflow or Reddit, or any number of slack/discords, so I don't know how I'd address that problem, but it's true.
https://users.rust-lang.org is moderated by the project. It is linked from the https://www.rust-lang.org/ footer and more prominently from https://www.rust-lang.org/community. Searching for "rust forum" it is the first thing that comes up.
Reddit is also moderated, but the cultural issues of that whole site, as well as those of StackOverflow, are well known by now.
I do my best to set a tone and lead by example whenever possible. Most of the times I've seen threads turn sour, it is usually catalyzed by people being unwilling to listen and acting hot heatedly to begin with. I've seen r/rust discussions where the article being discussed was far more critical of the language/toolchain than this one, but with far more constructive communication style and substantive analysis. The quality of the conversation in those cases have been much better.
Feel free to point me towards toxic community behavior and I'll do my best to address it through every mean available to me. I can't promise that there will be dramatic changes, but I certainly do my best to call out bad behavior and try to foster a space I can be proud to belong to. Then again, I do not spend much time in any of the sites you mention, so I can easily be missing bad behavior.
I would also say that even if you don't want to interact with people (for any reason), that's not an excuse to not seek out official or unofficial documentation. There is a non-comprehensive list at https://www.rust-lang.org/learn.
The OP had resources available to learn how to deal with errors in a more idiomatic way than he did:
- https://doc.rust-lang.org/book/ch09-02-recoverable-errors-wi...
- https://doc.rust-lang.org/rust-by-example/error/multiple_err...
- https://doc.rust-lang.org/rust-by-example/error/multiple_err...
Yes - a clear sign you have not found a good application for safety, security, and low-level control vs developer speed. Systems, safety critical, embedded, etc.
Why it expanded beyond this is not clear to me, other than hype and falling into a gaping void in distributed systems development that Go never filled for some reason.
It really depends on what is meant by "better." The thing I like about C++ is its problems are well-known as is how to work around them. The thing that concerns me about Rust is we don't know all its problems - in practice. We will eventually, sure.
Sometimes I don't think we pay enough attention to how much our collective experience with a language matters.
Therefore, the lifetime is expressed via an additional abstraction requiring the associated language syntax, compiler design, additional rulesets, etc.
Why would the same concept not be expressible as it's own data type, that would then be passed as data? In this case, you remove the additional abstraction. It seems like Jai is going that route, where you pass an arena type instance around and interact with it.
You may remove an abstraction, but you'd also lose efficiency.