I'm curious why I've seen this sentiment repeated in so many places, I learned Rust once 5 years ago and I haven't had to learn any new idioms and there have been no backwards incompatible changes to it that required migrating any of my code.
I'm curious why I've seen this sentiment repeated in so many places, I learned Rust once 5 years ago and I haven't had to learn any new idioms and there have been no backwards incompatible changes to it that required migrating any of my code.
This attitude works in carpentry, but not in software. You need to get proficient, but your tools will keep evolving, like everything else in the software world.
You can, in fact, learn C exactly once. Or any number of other languages. The entire argument being made here is that the world you're suggesting is a problem. Software developers should not have to continually relearn their tools and it is abnormal to suggest they should.
I'll take C written by people who've learned and improved since then any & every day of the week.
- a lot of code now uses mix of witness types and const generics
- with new borrow checker release they will do new iterators 2.0
Seems like coding on 5 year old Rust is like C++ 98.
L1: The edition system allows Rust to literally mutate the language. 2024 edition (if you begin a new Rust project today) has different rules from 2021 Edition, from 2018 edition and the Rust 1.0 "2015 edition". These changes aren't exactly huge, but they are real and at corporate scale you would probably want to add say a one day internal seminar to learn what's new in a new edition if you want to adopt that edition. For example we hope 2027 edition will swap out the 1..=10 syntax to be sugar for the new core::range::RangeInclusive<i32> not today's core::ops::RangeInclusive<i32> and this swap delivers some nice improvements.
L2: Unlike C++ the Rust stdlib unconditionally grows for everybody in new compiler releases. So even if you stuck with 2015 Edition, all the time since Rust 1.0, when you use a brand new Rust compiler you get the standard library as it exists today in 2026, not how it was in 2015 when you began coding. If you decided you needed a "strip_suffix" method for the string slice reference type &str you might have written a Rust trait, say, ImprovedString and implemented it for &str to give it your strip_suffix method. Meanwhile in Rust 1.45 the Rust standard library &str also gained a method for the same purpose with the same name and so now what you've written won't compile due to ambiguity. You will need to modify your software to compile it on Rust 1.45 and later.
L3: Because Rust is a language with type inference, changes to what's possible which seem quite subtle and of no consequence for existing code may make something old you wrote now ambiguous because what once had a single obvious type is now ambiguous. This is more surprising than the L2 case because now it seems as though this should never have compiled at all. Type A and B already existed, before it inferred type A, now it insists B might be possible, but it may be quite a tangle to discover why B was not a possibility until this new version of Rust. If the compiler had rejected your code when you wrote it in 2015 as ambiguous you'd have grunted and written what you meant, but at this distance in time it may be hard to remember, did you mean B here?
Now the nonsense: There's a vague superstition that Rust is constantly changing while good old C is absolutely stable. Neither is true by orders of magnitude. If you really need certainty you should freeze actual hardware and software, or at the very least build a VM and then nothing changes because you changed nothing. If you'd have been comfortable upgrading to a new CC version, you shouldn't be scared about upgrading the Rust tools.
Switch to Rust 1.50 and now it's calling the stdlib strip_suffix silently, I actually wasn't expecting it to be silent, and obviously if they have the same exact behaviour (mine instead panics to show we're calling it) you wouldn't even notice, but it is a change.
But on the other hand, it could be a bug as the trait resolver is commonly mentioned as the buggiest part of the language. I'm scared of the breakage if they fix it though.
So we didn't bring str::strip_prefix from the prelude in preference to our custom trait, we made a string literal and those have type &'static str -- an immutable reference to a string which lives forever. So the "prelude doesn't win" rule does not apply for &str because it didn't come from the prelude.
If we were talking about a type which implements Iterator for example, new Iterator features would come from Iterator, which is in the prelude and you didn't specifically ask for Iterator so the things you did ask for beat Iterator. But here the language primitive type grew new methods, a thing which Rust does but many languages don't do - Rust has methods on pointers and bytes and anything, whereas a language like Java or C++ can only put methods on "classes" not the ordinary types.
I thought the builtins were defined in core and reexported by the prelude (they are defined in core, they're just implicitly in scope anyway).
But I still think expected behaviour is that builtins should have the same precedence as the prelude.
Compare to [this](https://play.rust-lang.org/?version=stable&mode=debug&editio...)