The biggest threat to Rust's sustainability
kerkour.com
kerkour.com
However, the ground truth is that the design of significant new language features basically stopped in 2018. The work now is shepherding through the language extensions the project already committed to in the first few years after 1.0. For example, const generics, which will have a stable MVP in the next release, was first begun in 2017. Generic associated types, which are still not near stable, in 2016.
And my own view, these remaining features are a nearly "feature complete" Rust. Future extensions will be either more niche (a lot of attention in the last few years has been aimed at features to make writing unsafe code less error prone, which wouldn't visibly impact users who write only safe code) or less substantial (such as a syntactic sugar that would improve a lot of users lives, but not deeply change how they write code). And that's actually very good.
Regular releases of the compiler are awesome for the same reason continuous deployment of web apps is - each release only packs a small number of features. The chances of something breaking are much smaller than if it was a massive release of hundreds of features, all of which need to be tested in isolation and then with each other. The releases page (https://github.com/rust-lang/rust/blob/master/RELEASES.md) shows how rare it is for a fix release to be made. Even when it is, it's something minor.
Making the language easier to learn is a high priority. Many people are working on this actively right now - better documentation, better error messages, better IDE experience and so on. OP has misdiagnosed the root cause and blamed something that actually makes it easier to learn the language.
This psychological tinkering isn't helpful. People can push unfinished stuff in any situation. E.g. you can close it off 5 months in and then stabilise for a month.
I don't think the OP is having trouble learning. They're having trouble with the almost-monthly changes.
I'm curious, what in there would make someone have to deal with the changes?
But they don't in Rust. My example of Min Const Generics is an example of this. Async-Await (developed by GP on this thread) was also delayed to give it more time to bake.
I urge you to look at the releases page (https://github.com/rust-lang/rust/blob/master/RELEASES.md). Look at how few user facing changes are made with every release. This is a good thing! As long as you're ok with skipping these and the performance improvements, you can stay on an older release for basically forever. Most Rust libraries are conservative about their minimum supported Rust version (MSRV) so there isn't usually a push to upgrade at all.
If the OP wants a compiler and toolchain that only changes every six months, that's already available. He can stick with the same compiler for six months or even longer with 0 downsides.
if you work on safety/security critical systems upgrading the toolchain is considered like changing the tires on a moving vehicle. We have introduced and many weeks later discovered critical (and hard to trace) bugs simply by changing -O2 to -O3 in gcc that ended in sporadic crashes when cross-compiling for 1 specific platform. (which is a change much less severe than upgrading gcc itself) And I'd be surprised if upgrading the toolchain wouldn't potentially introduce similar hard to trace issues in rust.
My point is that just because the first 2 months after upgrade look like there were no required changes in code doesn't mean there are none. I see rust being used in very large companies for internal projects, test harnesses, and other glue/plumbing. And the places I know are really reluctant to go all the way in and substitute their ~30 years of experience with C/C++ with something that remains a constantly moving target. To be fair there are other reasons such as culture, and distribution of skills across the team that drive these decisions but my main point still holds (i think).
I mean, even with C, there is a very circumscribed subset that you use for "safety critical" applications.
2) People are banging on about Rust not being stable but the Rust Embedded guys DO lag for stability--so you can have stability if you choose. And Rust is by far the best language I have seen about being able to stay on old compiler versions and still use newer libraries.
3) I find crappy libraries to be the biggest threat to Rust's sustainability. There was a big "Gold Rush" mentality and a whole lot of unqualified people built a whole lot of crap libraries with no good way for someone to come along later and to flag "That's a crap library, please remove it from crates.io permanently".
Sure, this happens regularly in C and C++ because large programs inevitably depend on undefined behaviour, and changing compiler versions, optimization levels and target platforms is allowed to change that behaviour.
For the last five years I've been writing 99% safe Rust code, which is designed to have no undefined behavior, and I think it's not a coincidence that I can't remember ever having a compiler update break code at runtime. Once in a long while a compiler update will fail to compile some existing code, but that's not a safety issue.
The idea that C and C++ compilers are somehow more stable across releases is a mirage. https://lwn.net/Articles/845691/ https://lwn.net/Articles/845775/
This sounds more like undefined behavior in your codebase than a compiler error. I don't know Rust but I'm pretty sure the whole selling point is that you won't run into problems like this.
As an aside, the clang bug would also affect Rust if they used that type of optimization (assuming strict aliasing rules).
[0] https://lists.isocpp.org/std-discussion/2020/10/0882.php
No, this bug cannot affect rust, because rust wouldn't allow to pass into a function three mutable references pointing to the same object. It wouldn't even allow two, nor one mutable and one immutable. Either it pass one mutable reference, or any number of immutable.
It doesn’t happen often, but it does happen.
Anyway, Rust has found plenty of noalias bugs in clang, which is why it still doesn't compile with noalias optimizations turned on.
It absolutely happens, but less often than you would think.
Rust has a tool named "crater" which compiles and executing tests for every package uploaded to crates.io (and some which are just on github).
It's not perfect but supposedly it catches quite a lot of bugs.
The most used enterprise OS, Windows, is rapid release too -- every 6 months, coincidentally! But there's a LTSB branch you can use. Java releases every 6 months too, and that hasn't halted enterprise adoption. Similarly with C#, not every team jumps to the latest language level just because it was released. Teams should pick language updates at a speed that suits them -- but hopefully not so slowly that moving to newer releases becomes difficult.
Similarly with Go. Why should it be any different with Rust? To the extent that enterprises are using the latter two in massive numbers. The key thing is, as others have noted, is stability and a lack of breaking changes.
Exactly when it comes to Java, even though there is now a 6 month release cadence, take a survey of which version most are using. Certainly every time I bring this up, someone pops up and says, "I'm using 11" or "10". But the vast majority of "enterprises" are at max, Java 8. And they'll remain on 8 until something forces them off of it. Enterprises by nature move at a glacial pace. So their reason for adopting Java is not because it's "moving fast".
I was replying to the parent poster, who said that moving fast is a roadblock to enterprise adoption. Whether enterprises adopt Java because it's moving fast is another question altogether. Certainly no one is deserting Java because of the decision to boost its release cadence.
> Enterprises by nature move at a glacial pace
I think it depends on the enterprise.[1]
Cyber-Security has changed the game for many enterprises very fundamentally. Well-run enterprises now patch more promptly than many consumers -- at least, certainly the consumers who don't auto-update. Well, unless they want a Maersk-like incident[2], or be infected by ransomware. Maersk's incident cost it $200M if you believe Forbes.
About slow JVM upgrades, a lot of that is a cost/benefit calculation or poor technical leadership. CIOs and COOs (or audit, for that matter) have no interest in which Java version you use. The only questions are: Is it secure? Does it make commercial sense?
For actively developed software, staying on a recent-ish Java isn't a problem (many good enterprises have adopted Devops in some shape and form -- just add a task to your CI server to test on the latest JRE) once your engineering team has crossed the Java 8-to-11 hump. If you do that, you get to not pay Oracle $$$ per desktop/server every year (or you could use Corretto etc, but most enterprises will choose to pay Oracle). Or you could simply upgrade for the productivity & JVM improvements.
Legacy products not in active development are another matter, but even there -- the cost of not getting security updates is too high nowadays, so you have to spend money to secure it -- and legacy software has other costs too[3]. So unless you're a developer working on a legacy app, or an app who's design is so poor that it's locked into Java 8, there's no reason you couldn't be on Java 11 soon and get on the rapid cadence train yourself thereafter. It's really about how nimble your team is.
Of course, you could be unfortunate enough to work in an enterprise that doesn't take cyber-security seriously, in which case YOLO.
[1] https://news.ycombinator.com/item?id=25873325
[2] https://www.forbes.com/sites/leemathews/2017/08/16/notpetya-...
[3] https://arstechnica.com/tech-policy/2021/02/citibank-just-go...
Sure, but there's also things like how long will the current version be supported if there are security issues, or similar. People also want a version that will be supported with bug/security fixes for 6 or 12 months vs "Oh it's broken? Upgrade to head."
> This psychological tinkering isn't helpful.
The former comment is thoughtfulness about the ways that a system of work influences contributors mindset and thereby project quality. Even if the specific conclusion was incorrect, the earnest attempt is necessary to project health. If you disagree, you probably want to short-sell Toyota stock.
> you can close it off 5 months in and then stabilise for a month.
This doesn't help. If a release happens every six months then regardless of what you do during the release cycle, you are faced with situations where someone has a work item just about ready to ship in release X, but not quite, and you face enormous pressure to ship it in release X rather than in release X+1 six months later. On the flip side if you do force it to slip to release X+1 then that's several months of users not having the benefit even though it's ready.
If you're releasing every six weeks, there isn't any such pressure. Less work is shipped prematurely, less work is shipped later than necessary, and developers are less stressed.
And it has been a game changer if you ask me, Jira tickets don't pile up in the test lane, testers don't have to do one big regression tests at the end of the sprint just to sure. Sometimes even making them work overtime just to be sure. The code area that introduced new bugs is way smaller and the bugs have become easier to trace down.
Only if Rust has an awful leadership team organizing those releases. Strong leadership and careful release planning nips this right in the bud. "Your feature was only 'finished' a week ago? No way in hell is it making the release. See you in six months."
The other view is that shipping less frequently encourages features to be shipped fully baked and matured, with plenty of time for careful thought and attention given to their design and implementation.
> shipping less frequently encourages features to be shipped fully baked and matured,
Right, but this is just a view. A significant part of the industry believes that shipping less frequently discourages this. We've found that shipping more frequently allows us to take our time and fully bake and mature features in Rust.
Developing a compiler for a complex language is very different from developing a webapp.
Perhaps I'm being too conservative but I'd have more trust in the language if things were moving slower especially that rust positions itself as a systems programming language fit for production (today). Which is odd because what I want from something that ticks these 2 boxes is interface stability. I have more confidence in Zig or Nim for this reason. Give it another 5 years and it will be a similar mess as C++, or worse: Python (which ended up rolling out v3 which wasn't backward compatible with v2). Also the "safety/security" argument which is their big selling-point which goes out the window as soon as you pull 3rd party crates (as is the case in most of the projects).
> Also the "safety/security" argument which is their big selling-point which goes out the window as soon as you pull 3rd party crates
Not at all. Rust's safety guarantees work in practice. In years working on our largish Rust project we practically never have had to deal with memory corruption or data races.
They don't just work in practice. I spent 3 months last semester being taught in the separation logic "Iris", which is used to formally prove the safety guarantees of Rust as part of the RustBelt[0] project. That was under Lars Birkedal, for anyone curious.
Rust is a language I love doing actual work in, but it's also one I really like from the perspective of the theoretical backing.
[0] : https://plv.mpi-sws.org/rustbelt/That's, uh, a rather bold assertion. Perhaps you could elaborate on why you feel it's "broken by design"? I've never heard anyone take that position at all, much less make an implied claim that it's a widely-accepted position.
Do you realize that at this point Rust is way more stable than those two languages? It's not a critique at all as they are much younger, but these are really bad examples to compare with.
Can you specify, what are these flawed principles? And what would be a better system? Thanks!
This is just a report of the voices of the people I'm converting to Rust because they are never heard.
The compound effect of small and fast changes is complexity.
Uncontrolled complexity is the thing we want to avoid as it's fatal to any project.
Yes there are editions. But from a newcomer's point of view they only add complexity.
I'm convinced that short release cycle and feature 'bloat' are related. I simply don't want Rust to become the new C++ (which is the feeling of a lot of people).
New RFCs
No new RFCs were proposed this weekThis shows that the rapid pace of change already started to slow.
Software development / computer programming is complex. Hiding complexity is bad. News at 11. /s
So, that said newcomers are free to pick their poison regarding tech stack, language, etc. They can use something simple, easy, friendly, and sort of self-contained. Let's say Ruby on Rails, Django, or C# stuff. Inevitably they'll very soon run into the problem of managing dependencies, platforms, native code, security considerations, performance issues, etc.
Everything is a trade-off after all.
I'm confused... C++ doesn't have a short release cycle and it became feature bloated, so how did that lead you to conclude that the short release cycle of Rust is causing Rust to become feature bloated like C++?
Most of the problems with C++ come from the long release cycle and cause the bloat you're talking about. C++ rushes out unfinished features (see std::visit for a great example) to make a release window resulting in unfinished half working features that are horrible to use full of footguns.
Did you mean to link somewhere more specific?
https://medium.com/pm101/spotify-squad-framework-part-i-8f74...
1. Rust has very strong stability guarantees. If you want to you can continue coding like it's Rust 1.0 even on the latest compiler.
2. The rate of releases is independent of the rate features are added. Nightly is a playground for feature additions and whatever else. Many may not ever make it into stable, and many might hang around for many years before they are read to be stabilized. A consistent release schedule of every six weeks, whether there's much new or not, means there's no harm in delaying something for a release or three. This vastly reduces the pressure compared to a 3 year release cycle where missing the window means a very long wait.
Rust's releases tend to be very small. Even the big async addition was only the async MVP, not the final product. I think this is probably the source of most complaints because it does introduce some genuine churn for async projects.
But as always this is hard to discuss in the abstract. At least not without some idea of what features people think shouldn't have been stabilized or which they think were rushed.
Btw, here's a good article that attempted to look in to this more objectively:
I also understand that Rust is quite backwards compatible which is good but a planned better version of releases would be easier for everyone to keep track, update codes, etc.
As long as the compiler remains backwards compatible nobody forces anyone to rewrite programs that deliver their requirements at the time they were developed.
Major compatibility breaks occur on a very long time-frame and most certainly with a version bump prominent enough to draw anyone's attention. Personally, I expect builds to suddenly break on dependencies rather than anything else.
It's a non-issue.
There have been at least two cases where Firefox build broke due to having a too recent version of Rust installed. The stability guarantees may be fairly strong but it's definitely not perfect.
Of course it's good that they fixed the UB.
I understand what you're saying, but anyone who knowingly relies on undefined behavior deserves whatever pain they get, and anyone who didn't know they were relying on undefined behavior, needed to know about it.
There hasn't been a big feature since async/await, and the noise around that is now in library user space - as was to be expected.
There is a rust 2021 edition coming up, but that is also looking to be very modest with very few breaking changes. Like adding `TryFrom` to the standard prelude, and deprecating missing `dyn` keyword for trait objects.
It's the classic elevator issue in reverse. If you want to make an elevator faster, put up mirrors so people look at themselves instead of their watch.
Rust appears to change fast, because the changelogs are so detailed, but actually it's stable. Maybe we need to hide the detailed changelog and replace the main one with "minor bugfixes and constness updates".
The transparency is hugely appreciated by many. It's just that the approving voices are usually silent while the disapproving ones are always loud. Don't let that mislead you. You are doing great.
While perhaps not a large change in practice, this seems like the sort of thing that incurs a large cost when it comes to updating your mental model of how the compiler works, what it can and cannot do, and what options you have when it comes to implementing something.
It's like how you can get some weird set of complex rules and after a bit of time and practice you can just apply them without thinking much about it. However if you suddenly change those rules - even to make them simpler - you'll have to spend awhile readjusting.
It doesn't make the changes bad, but it might explain why people trying to keep up with Rust feel it's changing more significantly than it actually is.
1. Write some code that does something tricky with borrowed types
2. It won't compile. Search online for the error message. Find the Rust github issue about adding support for doing things that way.
3. Try to find or think up a different way to write the code. Go to 1.
GP is referring to changes that make compilation succeed at step 1. These changes will save newbs from many hours of frustration. The cost of these changes is minimal. Actually they free up a lot of mental capacity currently used for workarounds.
I'm really happy with Rust and the steady progress made by the core team. Rust stable is really excellent to work with.
Trying to keep track of what workarounds you do and do not need to use is hard. Removing workarounds is good, but still an expensive step. Applying a large set of rules can be quite easy after an adaptation period, but changing those rules remains hard. Even if the new rules are simpler.
I'm not saying Rust shouldn't be making these changes. I'm just saying I think this might be part of the reason why you hear comments about how hard it is to keep up with Rust.
Why?
If you simply do NOT update your model won't that work just fine? You would continue to avoid certain constructs that used to bother the borrow checker; your code would work fine, and the compiler wouldn't complain exactly as it used to.
I'd guess most people using Rust and checking the changelogs are people who are interested in keeping up with Rust. They are likely to update their mental model because they wish to.
And as a result, they often have to deal with these 'expensive' updates which makes it feel like it is difficult to keep up with Rust.
Contrast this to e.g. Go, which has a ~6 month update cycle, and most of the updates are boring. The main thing relevant to me personally for Go's recent 1.16 update is embedding files, and that's more of a "I can use it when I get to it" thing. Rarely does a Go update require action on my part, and since I started using it full time January last year, I've NEVER had to change any existing code. Neither required, nor because the language has solved something more clever.
Granted, that could be considered a bad thing, and I wouldn't mind some additional features to reduce the amount of code I have to write and maintain, but still.
You will get broken code if you rely on nightly features or if you change edition. My nightly code breaks about once every few weeks but everytime one or two features begin moving into stable and it gets closer to being on pure stable rust, not requiring any unstable things anymore.
So really, if you're writing rust to against stable rustc, you don't need to pay attention to much.
Rust's stability guarantees mean that you don't need to take any action at all.
Breaking changes (unless soundness is involved) only happen with editions and even when a new edition comes out and you update the compiler, you still don't need to do anything unless you explicitly change the configuration of the project to the new edition.
The only thing you might want to do, if you use clippy (a linter that comes with the rust toolchain). Is to check whether it complains about your code due to new check. If that's the case, you get told what to change and why.
Not sure I have the same experience or agree with that. Sure, Rust has a 6 week release cycle, but most of the time the releases are bug fixes or moving library additions into stable. Take this release for example: the only change is ARM support on Linux and a small update to the test framework. I’d hardly describe that as bloat.
https://blog.rust-lang.org/2020/12/31/Rust-1.49.0.html
> As a rust developer, I need to remain up to date with the latest developments in order not to produce code that is obsolete as soon as it’s released
Clippy should help with that, it usually flags deprecated code or better/more up to date ways of doing something. I don’t think you need to keep on top of every RFC, just use what you need.
I can relate to that. It would be great if new language features that make it into the stable version would require a contribution to Rust's documentation in a way that is easily discoverable by interested developers. Which brings me to a more general issue. Blogs from eager developers, who want to land a job in Silicon Valley, which don't contain any direct nor indirect information which could help readers quickly determine if an article is outdated or not.
How difficult can it be to add a date to an article or the version of the Language/framework in question? It always makes my blood boil when I have to find out by myself that a certain blog article, while it may be written well, isn't relevant any more.
In regards of Rust's own documentation some form of diff system eould be great. Last time I looked intonusing Rust was more than a year ago. I would love if I could enter a date or version, and get displayed all changes to the documentation and language between then and now. It would also be helpful when developers have to take over maintenance of code from a former colleague who isn't available any more.
I knew neither language, but try as I might I just could never get going with Rust. The syntax is obscure, the concepts are complex. There is also no real IDE for Rust.
Meanwhile Go was much quicker to get working code with, and when combined with the excellent Jetbrains GoLand IDE, my initial spaghetti code was soon transformed into a cleaner and maintainable format. The Go community on Slack is also a great resource.
I appreciate Rust is more complex than other languages and much less easier to pick up and learn on the job though. It definitely takes a lot of practice to get to the point where traits/lifetimes/ownership etc feel like brilliant tools rather than needless complexity.
Comparing a language with a fairly significant runtime and garbage collection to a language with basically no runtime and strict (albeit largely automated) compile-time memory management is comparing chalk and cheese. You might as well say "I tried C++ but ended up going with Python because it was quicker to code" -- of course it was!
See here for more details: https://nim-lang.org/blog/2020/10/15/introduction-to-arc-orc...
This is why I reach for Go by default when writing CLI tools. You will get your job done faster, and it will be much easier to understand and maintain. You will be trading off many of the static guarantees that Rust gives, but it's worth it for CLI tools, most of the time.
If you are writing code with strict performance requirements, then consider Rust. Otherwise you'll likely be adding a whole bunch of complexity for not much gain, and your code will require much more cognitive overhead to understand and contribute to.
In c++ there are foot-guns on every turn. Follow the links for some goodies:
https://en.cppreference.com/w/cpp/language/value_category
https://en.cppreference.com/w/cpp/language/reference_initial...
https://en.cppreference.com/w/cpp/language/template_speciali...
https://en.cppreference.com/w/cpp/language/overload_resoluti...
Building cli tools in crystal is fairly easy thank to the standard OptionParser library. `colorize` is almost perfect, too, in case you want to print some ascii colors. And just like ruby, invoking some shell command is simply wrapping the command with backticks. and FileUtils has ton of features.
Too bad Crystal now only works in POSIX.
https://old.reddit.com/r/rust/comments/m7seki/the_biggest_th...
General consensus both here and there is that the article is pretty roundly wrong, but that it’s probably still worth discussing a bit, largely to contemplate where this (mis)perception came from and what can be done to improve it.
It is kind of annoying when big libraries that are generally touted as the way to do X require nightly, but again that's my experience as of years ago. Nightly should be understood as a place where churn happens. For me, stable releases have never been anything but what it says on the tin.
> I’m a fan of the Pareto principle: 80% of consequences come from 20% of the causes.
This reminds me of the claim that most users only use 20% of the features of a given application.
What is often forgotten though, is that different users will often need different 20%.
Yes this is a piece of opinion, not a scientific measure of anything. This is just a report of the voices of the people I'm converting to Rust because they are never heard.
The compound effect of small additions every 6 weeks is complexity.
Yes there are editions. But from a newcomer's point of view they only add complexity.
Feel free to disagree, but I'm convinced that short release cycle and feature bloat are related. I simply don't want Rust to become the new C++ (which is the feeling of a lot of people).
That is something that is missing in the article. I think it is valuable to know about these opinions, so thanks for sharing them.
Both here and /r/rust (https://old.reddit.com/r/rust/comments/m7seki/the_biggest_th...), this has been pretty thoroughly debunked. If you still hold your position after reading all the comments, I’d be interested in a rebuttal.
As I said over in /r/rust, I think this claim of yours is still interesting because it’s a matter of perceptions. I’m certain that this perception is erroneous, but impressions still matter. If you want to succeed, it helps to manage public relations proactively.
I've bookmarked the page and will for sure read all the comments this weekend, they look very interesting (especially yours, that I've flew over)!
That being said, I stand by my point: Short release cycles are an illustration of The Compound Effect.
> A programming language is a platform. You can't build a thriving ecosystem on top of an unstable platform. We need, as a community, to find a solution to bring calm and focus to Rust, and then we will be able to stabilize and build a great ecosystem of libraries on top of that platform.
> Short release cycles are suitable for products, as you can remove features or UI elements, and thus complexity can decrease over time. But for platforms, it means that you can only add things, as removing parts of a platform will break backward compatibility. Thus complexity may only increase over time.
I would love to see almost "empty releases" in order not to add non-essential features and thus avoid feature bloat.
But then, what is the point of short release cycles if it's not to add features? Wouldn't longer releases cycles make more sense?
And what would be the point of sitting on small, well tested, changes for six months or a year? What if it's two or three years before the next major feature is ready for stable? Do we have to hold back all the small improvements too?
For example, making a function const allows it to be used in more places. This can be a big benefit for users. It doesn't help anyone to delay that once it has been decided it is const.
This is no indictment. Rather, it is a necessity, and a prerequisite to industrial success. The world is complex, and will not adapt itself to a language. A language must adapt itself to the problems the world needs solved. Failing to address a need sends users to languages that do not.
The best that can be done is to start as simple as possible, and then develop as required. (C++ did did not get the luxury of starting simple, but only as simple as was, then and there, possible.) Every language that succeeds becomes, eventually, as complex as its users can handle. The limit is human-scale. The pressure to grow has no natural limit.
There is a real sense in which added complication is needed to give an experience of better simplicity. We see this frequently in releases: restriction X has been removed. The surface texture of the language has become smoother, at the expense of the implemention, which needs to grow to implement the relaxed restriction.
It is always easy to justify removing restrictions, simplifying the description of the language. But this is how languages grow. As restrictions are removed, code in the language becomes simpler. The language takes on more responsibility, so the programmer has less. This is a positive development.
Rust is already a language that caters mainly to professionals, that demands serious education to adopt successfully. The majority of programmers will never succeed in adopting Rust. That was an early choice.
Every language is determined by its choices, which box in unpredictable later choices. Sometimes the right early choice forces what seems like a wrong later choice. That is our lot as humans in an unfolding world.
Celebrate Rust's trajectory as exactly what is needed to mature and succeed in a difficult world.
I was under the impression that rust is pretty stable?
Like web browsers get updates on a fast cadence and it rarely breaks existing web pages.
There is not a lot of the former, but there is some of the latter, and even if it's self-imposed, some people do feel that pressure.
As a counter examples, Go release roughly every ~26 weeks and mostly has releases with minor updates. Chromium releases every 6 weeks but not every release has major updates; they are mostly bug fixes and minor improvements. Even Android is decoupling its system services into components which can be updated through the Play store at a much faster cadence than their yearly releases.
I agree that Rust needs to now focus on polish over new features at this point, but I'm not sure that Rust should've done something differently, especially around its release cadence. I don't think it would've been a good contender for serious companies if they hadn't invested heavily in async, for example.
Isn't that what the article is arguing for? C++ has a standard that goes through the ISO process (horrible as it is) to be vetted and finalized and implementors need time to catch up. They're moving faster than they used to but it's still 3 years between new releases of the specification and a little more than that for implementations to catch up and become stable.
* long term support
* choice, in particular in building shared libraries.
While a lot can be argued on the first point, the community seems to be actively against anyone who wants to use or build stuff with shared libraries. Shared libs are extremely useful in resource constrained environments like routers, and the debate on who should update things (distro maintainers vs project maintainers) is still very well out there.
But breaking compatibility every compiler release is a huge pain the butt, and will force those who need shared libs for one reason or another to work with older, unmaintained compilers, with many projects being unable to compile there (the only "edition" is 2018, 4 years now which is starting to look like C++ standard levels of time).
Because like Potter's projects, who the hell ever needed an LTS release? Can't/don't want to update everything every week? Your problem. Now try to choose a single compiler release for your distro.
IMHO, either you have too many big features on each release, and therefore the "editions" should track that, or those are not that big of a deal, so no edition bump is needed and we can focus on binary compatibility, maybe? maybe have sub-editions, like 2018.3?
So yeah, I love rust, and this is really the only bad thing I have to say about the project. Honestly, if there was an LTS release, maybe just one for rust "edition", maybe use editions better, I think everyone would be super happy and most problems would be resolved.
As for LTS, there is indeed a stand-off with Linux distros. Rust bets on Chrome's update model, where updates are small and backwards-compatible, so everyone is on the latest, and versions don't matter. Linux distros want Rust to have Internet Explorer update model where there are only updates every X months or years, and developers have to specifically test and work around to support multiple old versions.
Note that Editions aren't language versions. They're like "use strict" in JS. They only toggle warnings and small parsing details, but there's only one Rust version. Every Rust edition can use any Rust feature, as long as it parses. For example, everything new added in 2020 is available in the Rust 2015 edition.
I'd like to point out that this effectively means "it's not against shared libs, but it will actively ignore anything needed to work with them"
The "move fast and break things" is fine, as long as you are the last link in the chain. Rust is the first.
> ...there's only one Rust version. Every Rust edition can use any Rust feature, as long as it parses. For example, everything new added in 2020 is available in the Rust 2015 edition.
IMHO this is a great feature...for the last link in the chain, not the first.
Note how this is only possible since for now there is only one rust compiler. As soon as GCC or others get ready, how do we sync between features supported? IMHO eventually the "editions" will be treated as minimum version to compile with.
Also, as more and more software is written in rust, lack of lts will force the users to update whole systems every 2 months (and making dynamic linking impossible will only worsen things). I still get 30Mb/s flat connections, and even with that multi-GB updates are a pain. Now imagine that for countries that are worse off.
It's not impossible to work with, it just makes a lot of management things a constant (small?) pain that we had eliminated before.
There are libraries that enable this: https://docs.rs/abi_stable/0.9.3/abi_stable/
static vs dynamic is a linker (and LTO) problem, we can't start asking everyone everywhere to change all their code.
Although the library does look nice for some use cases
I definitely would like better language support. But IMO the solution shouldn't just be "flip a compiler switch and all your normal data structures have a stable ABI" either.
What I would really like to see is a cross-language ABI (that's more fully featured than then C ABI), that can be opted into with `repr(polyabi)` or whatever it ends up being called.
This doesn't work, because new features are not only added to newer editions, but to as many editions as possible. The vast majority of new features, when they land, are added to every edition.
The Rust stable ABI is simply the C ABI. This doesn't work so well with features like generics as you mention, but it's good enough for interfacing with separately-built shared libraries.
The Rust Evangelism Strike Force could take a few hints from the actual military about how to design a language to a spec. By all means, iterate with actual code first. But do not expect third party users to use the "whatever rustc does is the spec" releases for actual production work. Use those releases to hammer out the details, draw up a spec, then release the spec (under an open license of course) and let the implementations flourish.
You can argue that Rust could do better, but using the military as an example of doing it "right" is kinda funny.
1) The military changes specifications all the time, which is a big reason why so many projects go over budget by 300%. Look at the B-1, B-2, F-22, F-35, Space Shuttle, etc. All boondoggles caused by making tons of last minute changes that blow up the entire project.
2) The military is moving away from Ada. The F-35 avionics code was all written in C++. Apparently they decided it was easier to hire existing C++ developers than to teach people Ada.
That said, it is natural that any successful product goes through the explore, expand, exploit phases (see Kent Beck). And this is perhaps a sign that Rust is approaching the exploit phase, where changes should be slower and focus shifted to reducing overhead.
Perhaps a future Rust edition (next after 2018), will have a list of features removed as it's main selling point?
Still I agree with (out) boats. Rust should complete it's main concepts first. Then we can tidy our room. Promise?
That being said, you’re not wrong that people deserve to be paid for their work, and the foundation was created in part to help work on this topic, to help the project pay bills and encourage employment, but I’m not aware of many, if any, open source projects as large as ours where everyone or even the majority is paid.
Wait, why would we want to deter big companies from using and supporting Rust? That makes no sense to me. This pervasive big-company-envy is something that I just can't grok here at HN.
What I find most unproductive in Rust is the idioms that don't find their place in the official docs. Steve Klabnik wrote an excellent comment here in HN 4-5 months ago about how to use a thread pool which illustrated my gripes with Rust PERFECTLY: https://news.ycombinator.com/item?id=24992747
I understand this is not part of the stdlib. I do. But the officially blessed way without 3rd party crates is indeed quite hard to get right or to even write in one go.
Another thing that severely disappointed me is the lack of serious plans for Rust 2021 Edition. I really was looking forward to a terser syntax for a bunch of idioms (sadly in the meantime they flew out of my head and now I can't remember them).
The 6-week cycle is IMO not a problem. The changes have been fairly small -- but some of them very impactful, like the constant (pun intended) moving of functions from normal ones to `const` ones.
Rust is now doing the same. Few in the embedded space find it appealing, many of those who use C++ do (as it is certainly a cleaned-up C++, and a nice improvement in comparison), but too often not appealing enough to switch now, and some in the application space who don't know or don't remember the C++ lesson do adopt it now (sometimes out of sheer novelty) but will likely abandon it later for similar reasons C++ was largely abandoned in that space. So it is really competing for a pretty small and conservative niche -- albeit an important one -- and one with a strong incumbent. If it does very well, in 20 years we might find that 60% of the C++ space has switched over to Rust, and that's about it.
What Rust needs is focus, but it won't have it because I think some of its designers still believe in what C++ believed. That you can have a language that is both high-level and low-level, with the benefits of both and the downsides of neither.So it's being pulled in multiple directions, all while showing poor performance in the market (C++, at least, wasn't just hyped but actually popular). It's not even going after C++'s market seriously, but after the nonexistent market C++ thought it could occupy; the only market it seems to be actually competing over and doing well in is HN-front-page real-estate, the space formerly occupied by Ruby and Haskell. When I was at University in the late '90s, everyone was talking about Haskell will be the language of the future. With almost constant levels of hype, more than twenty years later, it still is. It turns out that for various reasons, when it comes to programming languages, hype and market performance can be completely out of sync for decades. Rust's designers need to choose between adoration and actual popularity. The latter will require some tough decisions. If it's going after the C++ market, it should make itself extremely appealing, irresistibly so, to C++ programmers.
I definitely don't get the feeling that C++ was that popular, I distintcly remember many Linus rants about it. It's just that after years of usage it carved its own niche.
However one pain point Rust does address is parallelism. If you want to use modern systems, and you're going with C++. Good luck. You're gonna need it.
As for the popularity, I think that's moot. But I do agree Rust can't be everything to everyone. One problem it will have for the forseable future, is the slow compile speed. But on the flip side, Rust has been super popular.
But it does one thing no other language does. Safe concurrency without GC. It's like a seatbelt in a car. Once you get used to it, you'll be paranoid its not there.
----
Where I do agree with article author was rate of change. IMO Pin should have never been added to standard library as it currently is. But async was rushed, for god knows what reasons.
if you're doing modern stuff you just use a task-based parallelism lib and pass things by value with libs such as https://github.com/taskflow/taskflow, https://github.com/cameron314/concurrentqueue ...
I'm not sure who is it for, but if it's responsible for Pin and it's related unsoundness issues, that just makes me dislike it even more.
A language with BDFL could have, took a more principled stance and said no async until we prove Pin is safe.
> took a more principled stance
This is very insulting. Bugs are often found in every kind of software. Virtually no languages that exist, let alone popular ones, require proofs before landing new features.
To me it's not a bug. It's a foundational flaw. If Rust was a house, and a bug was a broken window, unsoundness issue would be water seeping into the foundation.
If standard library is unsound, that means pretty much everything derived from/relying on that functionality is unsound.
Adding unsoundness for the sake of pushing a feature out is just bad. It's cutting corners on essential things.
> they also could have said "ship it"
True. But if I know that BDFL is an asshat, then I avoid that project.
Here's why this matters. This response from you is much better! Because:
> If Rust was a house, and a bug was a broken window, unsoundness issue would be water seeping into the foundation.
Yes. Everyone agrees, in principle, that Rust being sound is an important property. Your criticism isn't actually about principles, it (appears to me, anyway) that it is about the specific methods in which we figure out if something is sound or not. You can argue that nothing should be added without formal proof, and that's a fine position to take, but at least it is a specific, actionable criticism that can be discussed directly.
By this standard, virtually all languages have "unprincipled" designers. This isn't even true of only async! We didn't (and still sort of don't) have a formal model of the borrow checker. So you can't really criticize async specifically in this way, you'd have to criticize the entire language.
The way I see unprincipled is two fold: 1) You're breaking your promise 2) In a similar situation behave differently
1) Pin was a problem from the start. Allowing it into std/core was a mistake. The fact they allowed an almost blatantly unsound feature is unprincipled.
I'm not 100% sure of the timeline, but near or before the release there were examples floating of a possible Pin unsoundness. And defense was, it's an obscure thing, no one would really use that in practice. The moment designer says, no one would use that in practice, is the moment they lost.
2) Yeah, I get async was a feature everyone wanted. By same measure, why not add self-referential struct. People want it. It's probably unsound but you can't tell. Maybe there exist a model that allows self-referntial structs.
Similar situation, different behavior
People do want it, and in fact, it is part of async, and directly related to the soundness issues you’re complaint about. The reason such things aren’t in stable is that, while people do want it, people wanted async more, and did the work. The work has to happen, features don’t just magically come into existence.
It doesn't appear to be unresolvable.
But what if the issue was unresolvable? Rust would either have to rollback a feature or basically say, we're sound, except for that part.
The attention thing said by Bjarne by himself when asked on Reddit.
I guess the dream of a perfect low+high level language will never die.
You seem to imply that it's fundamentally impossible ?
... and... doesn't it still work ? An awful lot of C++ applications are being written today, and that can be done at a pretty high abstraction level thanks to the type-level facilities of C++.
> . Few in the embedded space find it appealing, many of those who use C++ do (as it is certainly a cleaned-up C++, and a nice improvement in comparison), but too often not appealing enough to switch now, and some in the application space who don't know or don't remember the C++ lesson do adopt it now (sometimes out of sheer novelty) but will likely abandon it later for similar reasons C++ was largely abandoned in that space.
are we talking about the same embedded? most C shop migrate to C++. most car brands, and a lot of appliances, use Qt for their UI (C++)
C++ is nowhere near as dominant in the application space as it was in the early nineties. "An awful lot" in nominal terms for sure.
> are we talking about the same embedded?
Probably not. C++'s niche is "low-level with capable hardware." Some "embedded" software does actually run on very capable hardware.
what do you call "capable" ? C++ is routinely used on atmega328, a 16mhz uc with 2kb of ram.
You’re rewriting history here, friend.
Hardly anyone was writing embedded C++ in the 90s. Even nowadays I bump elbows with Developers that refuse to make the move from C in embedded.
If we’re talking Desktop apps, well... yeah, Windows was the new hotness, OOP was hot ‘n fresh, and Visual C++ was a BFD. Once more languages came about, people found ones they preferred over C++ (Java was a BFD).
As to your last comment, I’m guessing you haven’t worked in the embedded space with C++ if that is your conclusion
I wasn't talking about embedded in that section, but about applications, and not just desktop.
> Once more languages came about, people found ones they preferred over C++
High-level languages were used a lot before, like VB and other RAD languages. But the belief was that they'd be too slow for many applications, like servers.
> As to your last comment, I’m guessing you haven’t worked in the embedded space with C++ if that is your conclusion
That is correct, and yet the lower the hardware capabilities and the higher the required safety, you see more C and less C++.
Whereas Rust, to me at least, is 'ML-ish with curly braces'. So, a language firmly based in the ML heritage with C-like syntax. So, fundamentally working with types and 'typeclasses' and heavily leaning towards filter/map/fold/reduce/lift/unlift type of thinking. Sure, throwing funtions around as first class objects are not as easy or straightforward as it is in 'real FP' languages, but that's a trade-off I'm willing to take for the guarantees that Rust provides.
I'm genuinely curious what's the reasoning behind being able to assert that 'Rust is a cleaned-up C++'.
- Doing Option<T> -> Option<U>
- At what point do I do Option<T> -> Result<T>
- Should I transpose Vec<Option<T>> to Option<Vec<T>> now or later?
- Often reaching for algebraic data types
- How to map over this to collect it into what I need
- Ah, it needs to implement Hash, Eq, PartialEq ... SomeTrait to make it work the way I want
- Pattern matching all over the place
All of which to me mentally feels more like something along the lines of F#, OCaml or Haskell than C++ that 'normal people write'.
When I did my degree, C++ was taught in the second year and Caml Light in the third.
SML, OCaml, C++ and Haskell are all mentionned.
That's a brilliant metaphor to drive home the safety advantages of Rust! "It's a table saw that won't chop off your fingers!"
That's a "shut up and take my money" proposition. (And it helps that it's a really good table saw too.)
(As another aside, I got to the testimonial from an employer talking about the peace of mind of knowing the workers on the shop floor are safe and it "clicked" for me: you've got metrics and liability for job site safety so you can quantify that peace of mind. We still not there with software quality liability eh?)
"It's simpler than C++!". Yeah, Rust could become a bloated mess and still be simpler than C++. It's like saying that a mountain is not high because it's smaller than the Everest. It's not a good idea to use C++ as reference.
But Rust isn't complex: there aren't many features interacting in a special way with one another with a combinatorial explosion of interactions you need to know in order not to shoot yourself in the foot. (Move semantic difference between Rust and C++ are a good illustration of that).
Actually, in terms of number of different features you'll encounter when onboarding a new project, Rust is far behind JavaScript and PHP (PHP being the biggest example of how feature bloat doesn't kill a language, even if your language is targeted at inexperienced developers).
"Why I rewrote my Rust keyboard firmware in Zig: consistency, mastery, and fun" https://kevinlynagh.com/rust-zig/
In absence of good metrics for the kind of complexity we're trying to discuss I think we kind of have to rely on these sorts of first-person subjective reports from the field.
But it does need to be said, that the approach he was using with Rust was absolutely not the right tool for the job. The author should have been using traits. That's what they're for, and they definitely aren't an obscure language feature.
And that being said, the author mainly complains about features that also exist in C (macros and ifdef, and Rust's version are easier than the C one), would you call C a too complex language because it has macros and ifdef? (I actually think that C is one of the most complex programming language ever written because you need to store too much invariants in your head otherwise it's UB, but ifdef and macros aren't at stake )
- - - -
> I actually think that C is one of the most complex programming language ever written because you need to store too much invariants in your head otherwise it's UB, but ifdef and macros aren't at stake
Like I said, without metrics we're just trading subjective anecdotes.
Metrics for complexity of machines is a subject I find fascinating, ever since I read Ashby's "Introduction to Cybernetics" wherein he asks the question "How can we measure the complexity of a machine?" in the context of a formal system for describing machines (Cybernetics.)
There is also the concept of "Kolmogorov complexity" https://en.wikipedia.org/wiki/Kolmogorov_complexity
We could compare the sizes of compilers for C and Rust.
We could teach each to different randomized groups of students and see how quickly people learn to write (safe!) code in each.
Yes, this one guy made a wrong turn once. If you want to conclude from one user making a mistake that a language is complex then you're just going to conclude that programming is complex … Everyday, with every language under the sun, people make mistakes, great discovery.
I'm not blaming “the user®” here, I'm blaming the blog post writer who makes a mistake and concludes that his tool is responsible for it and that he should tell the world how bad the tool is.
> Like I said, without metrics we're just trading subjective anecdotes.
Well that sentence is pretty ironic given the previous one, nevermind.
> We could compare the sizes of compilers for C and Rust.
I wonder what conclusion you'd draw from such a comparison. That assembly is the least complex language in existence, followed by Brainfuck and Chicken?
> We could teach each to different randomized groups of students and see how quickly people learn to write (safe!) code in each.
Oh I actually like this one. For Rust, you'd need to run a study to find out, but for C the answer is trivial: Never. Nobody on earth know how to write safe C. Not even DJB, not even Theo de Raadt, or Richard Hipp, or Brad Spengler. For almost 50 years, the brightest minds of computer science have tried to write safe C code, and consistently failed. Can we conclude that this language is a little bit too complex for humans, or should we wait a few decades more?
I wish there was a C with a borrow-checker like Rust, but without everything else.
And what decisions would that be? Your post seems self contradictory to me because it implies that Rust is both too "low abstraction" to be "extremely appealing" to C++ crowd, and too complex and "hard to analyze" to displace C in use-cases that require portability and/or are resource constrained.
If there's anything we can learn from programming languages -- be they C, C++, Ruby, PHP, Haskell, or Java -- riding the hype-train led by PL enthusiasts and early-adopters is not a good recipe for long-term success (even if it is a good recipe for long-term hype). Like with fashion (and I think HN is more like GQ or Vogue than actual industry news; i.e. it is more aspirational and inspirational than descriptive or prescriptive), the languages people talk about and those they actually use for many years are usually not the same.
That's exactly what Rust is doing. It used to have a runtime, green threads and a GC, but it doesn't because that's not what C++ developers want. And recent development work has been focussed on const generics and const fn which are both keys things seen as missing by C++ developers.
Why would you want Rust to target lowest-common-denominator developers and become new VB or php? All it needs is enough momentum to become self-sufficient, which seems to be actually happening now with Rust Foundation and news of its usage in some major companies that can set the trends for whole industry (Amazon, Google, etc.).
Rust wants not that I wants. It seems people replacing NodeJS with it.
From the perspective of someone who's been writing Rust professionally for the last few years, the hockey-stick curve started kicking in in late 2020 or so.
But you can even have a rough estimate according to your own measure. There are roughly between 50K and 100K developers working at FAANG (maybe replace Netflix with Microsoft). How many of them would you guess are using Rust?
I don't think Rust and C++ have the same level of abstraction, for example. Rust has ADTs and pattern matching, C++ only has product types and std::variant.
There's a crucial distinction between input and output types in practice. For a given input type T, Rust makes it possible to abstract over `T`, `&T`, `Cow<'a, T>`, `Arc<T>` etc, by using a trait such as `impl AsRef<T>`.
However, Rust doesn't currently have existential types, so its ability to abstract over output types is more limited. You can implement, for example, `fn foo(&self) -> impl AsRef<T> + '_`, but you can't name that type. So if you want to return an enum, you can't write
```
enum MyEnum { MyT(impl AsRef<T>), MyU(impl AsRef<U>), }
```
Instead, you have to concretize the type somehow, either by boxing things up into a trait object (often but not always possible) or by exposing the generic param:
```
enum MyEnum<RefT, RefU> where RefT: AsRef<T>, MyU: Ref<U> { MyT(RefT), MyU(RefU), }
```
This is a real problem, though one that will be solved through existential types.
> Replacing, say, a concrete type with a trait is about as much work in Rust as it is in Assembly.
I'm not sure what you mean here. I'm not aware of any assembly languages which have traits. Replacing a concrete type with a trait tends to be pretty easy in Rust because mistakes are caught at compile time.
> I'm not aware of any assembly languages which have traits. Replacing a concrete type with a trait tends to be pretty easy in Rust because mistakes are caught at compile time.
I'm not thinking in terms of language features but abstractions. The best way to see this is to think how many different implementations to a code unit I can do without making the consumer aware? That number is significantly lower for low-level languages compared to high-level languages because things that can be hidden in high-level languages, like layout, storage and lifetime, must not be in low-level ones, hence "low abstraction." Changing something in one place is more likely to require changes elsewhere. Therefore, low-level programs are more rigid, more jigsaw-like, and their evolution more difficult.
It is true that a compiler that tells you if you missed a change helps a lot, but it doesn't change the nature of the low-level language, even though it improves its ergonomics (although it's not so simple, as sometimes even correct programs are rejected) -- you still need to do all the extra work, but it doesn't take quite as long.
Not really; Rust is very careful to avoid leaky abstractions, compared to C++. It's definitely "low level" in a foundational sense (even reminiscent of C in many ways) but the limited "high-level" features it does have are incredibly solid and highly usable.
Additionally at least on Windows, Microsoft still believes in C++ for doing the kind of desktop applications you are talking about.
All these scenarios aren't properly covered by Rust in its current state, even the Rust/WinRT project is doing baby steps, very far away from what VC++ offers today.
Haskell doesn't promise the type of control I need. Someone i work with rewrote our main control algorithm and proved it was correct (not in Haskell ,I just fear this problem ), but it took over a minute to run, and this PID loop needs to run at 5hz and leave some processor for other tasks. My c++ isn't proven correct but we have 15 years of production with it.
Rust promises to avoid some of the things we don't like about c++ while still worming in the real world. So of course I'm interested.
Oh, I do remember we had cool kidz writing implants in Go, C#
What a failure! That's why the NSA and GRU selected Modern C++!
He selected the wrong tool for the job. Take a look at Flawedgrace, it is written in modern C ++ and very complex to RE. It uses OOP heavily.
Rust is a subset of modern C ++
The Rust people have mastered Alexander Stepanov's vision for C ++
Have a look at Alexander Stepanov's Elements of Programming.
This post just a hidden marketing for his "Blackhat" book.
C++ didn't make any mistakes. The language didn't but the developers did.
It's pity that people portray C++ as dead and horrible lang.
The ecosystem of programming languages has become more like the Ponzi Crypto industry, where every night you get shiny cryptocurrency and then charge for consultations and speaking.
Apart from that, Perl is not a substitute for Rust or vice versa, regardless of the amount of typing involved.
It... doesn't, though? Rust's syntax is pretty aggressively conventional, from my perspective.
Looking at the punctuation symbol tokens, almost all of this is common to many languages: https://doc.rust-lang.org/reference/tokens.html#punctuation
The symbols that come to mind when I think about my experiences writing Rust are: - <> for generics - ? for early-return errors - Macro invocations require a ! - Match statements use => - ' for lifetimes - #[attrname] for attributes - |x,y| for closures - -> for return types
All the other common symbols I use feel too conventional to seem worth mentioning, like {} for lexical scopes, = for assignment, +-/ for math, foo() for function calls, foo.bar() for method calls, (a,b,c) for tuples, [1,2,3,4] for arrays, <>!== for comparison, "quoted" 'strings', / comments */ and //comments, etc.
I agree that might_fail()? and 'lifetime are different, but everything else I listed seems lightweight, and very common for languages to use symbols for. <> is common for generics from C++, but alternatives I've seen are [] and (), also symbols. Matches use =>, and C's switch cases use :, also a symbol.
Using macro_rules to define macros is pretty symbol-heavy, I guess?
Usually when I see complaints like this, they come down to complaints about the lifetime syntax, and not liking the use of ' for anything besides quoted strings.
If you disagree, could you explain how I've missed or misunderstood your point? Can you show some examples of normal Rust code that uses way more symbols than normal Perl?
From the outside (not actually writing Rust code yet) it looks like Rust saw C++ metastasize from an overcomplex big language into an even more overcomplex huge language, and then said HOLD MY BEER!
Encouraging people to go async / event based looks like a huge mistake to me. Code becomes much harder to reason about and you get a ton of additional complexity to worry about.
A much better way is to provide a layer that looks synchronous on top of asynchronous mechanisms. Like going for declarative programming, or make it look like "one thread per request" and have implicit timeout handling via exception you can catch or so.
I think the compartment threading model is one of the main reasons why COM is so successful.
While in fact Rust 1.0 was a bare-bones MVP, missing basic functionality, with an annoyingly inflexible implementation of the borrow checker. You couldn't print or copy an array larger than 32 elements! People still complain that the standard library can't generate random numbers and you need a 3rd party library to cast an integer to an enum (really!)
Since 1.0, Rust has been mostly filling in holes, and removing gotchas. Apart from async, a lot of changes can be summed up as "this obvious code didn't compile before for weird technical reasons, but now it just compiles".
Async started in 2015 with mio library, which was a thin wrapper over Linux epoll. People have recognized that it's tedious to use it, and proposed Futures in 2016, which made it easier. Multiple limitations of Future's APIs were became apparent, so in 2017-2019 there was a lot of work to remove known problems and annoyances. That's the async API: 4 years of real-world experience and simplification of async code. As someone who's used it during that time I can assure you that `async fn` today is easier and clearer than everything Rust had before it.