If the problem really comes from incorrect code in Firefox then I don't think that backwards compatibility is even possible. Consider the possibility that it was actually a bug in the Rust compiler that let this code pass. What should the compiler developers do if not fix this bug?
If, on the other hand, the code was correct, then backwards compatibility is definitely expected. The same holds for the format of the cargo files, btw. changing something like this during one major (or minor, depending on the release cycle) release is bad form IMO.
The mentioned case of C compilers and their warnings is an interesting grey area. Presumably it would still compile just fine, but as a developer you want -Werror and -Wall. In practice this often makes certain libraries incompatible after a compiler upgrade.
There had been a few cases where bugs in Rust had been fixed which did cause breakage, but fixes where rolled out slowly spread over multiple versions.
This included:
- Soundness issues around Self: Sized bound requirements and traits. (Big breakage bout early one in rust lifetime.)
- Soundness issues around something related to match statements and guards I don't remember.
- Something related to accepting invalid inputs, I think this included Cargo accepting invalid Cargo.toml files.
There was also a very small bit of accidental breakage which counted as a bug but affected close to no one so no one ever invested time to fix. For example a bug which only affects people running multiple tightly linked rust crates on older editions and doing unusual stuff wrt. macro imports and re-exports which where only valid for I think 1-2 rust version.
Then there was a bit of accidental stabilization, where things which should not be doable on stable where doable. If not found very early this was normally kept stable if possible, but I think there was at least one time where this "stabilization bug" needed to be fixed.
Anyway to cut it short:
1) Compilers are not perfect, this is also true for C/C++.
2) At least serve bugs (e.g. soundness bugs) are not treated as "de-facto" standardized/stabilized but are fixed (something I prefer).
----
As a side note Firefox is a bad example as they used some tricks to use some definitely not stable options on stable rust which is basically guaranteed to cause breakage at some point and not covered by any stability guarantees.
As another side note `#[deny(warnings)]` is also not covered by stability guarantees, the compiler is free to add new warnings any time (but will do so with a lot of care, e.g. preferably only with new rust editions, which also may make some warnings errors).
---
Also:
-`rustup` supports setting overrides, no reason to fear updates, just pin a older rust version in your create using overrides (if you need to).
- Idk. about his problems but I have yet to see a case where any breakage wasn't reasonable straight forward to fix (weather unintentional, intentional to fix soundness or due to an edition change triggered by me).
These days upgrades go much more smoothly, but on the first decade of the millennium upgrading your C++ compiler was always a major hassle as each version would fix many bugs, increase its standard compliance and start rejecting erroneous code.
It still happens today, but nowhere near as badly. I package FoundationDB for my linux distribution, and around GCC 6.x the build broke for version FDB 6.0. Why? Because the code used 'log' unqualified in their code (for logging), and some rearrangement of the libstdc++ headers to be more correct and caused the 'log' (math function) to come into scope. (The libstdc++ changes were the correct course of action, in my reading.) Of course, FDB also changed their code in the mean time so newer versions 6.1+ didn't hit this, so it was an old regression in an old version from a mishap in the standard library that had been a bug for like, years and years.
Tons of regressions like this happen all the time in the GCC/LLVM world. Every time we do a bump of the default C compiler, you can bet it will take 4-8 weeks while regressions -- from "This random thing enabled -Werror, again" to "Someone used a new feature but scoped the #ifdef wrong" to "Actual segfaults in libstdc++" -- are sorted out.
I would love to know what the errors actually were, maybe a deeper dive into what and why compatibility was supposedly broken. Did the rust developers know that they were breaking compatibility? Firefox is a pretty big high profile user of rust, a breaking change couldn't have just snuck by.
Firefox only cares about Firefox working with the specific rust versions they intend to support. They also use some hidden non document rust flags to use unstable rust options/features on stable (but increasingly less, the flag exists only for bootstraping rust itself and isn't meant to be used by anything else).
Which is fine for Firefox itself.
Just a problem for anyone forking of Firefox. (Or for other reasons trying to build it with a different rust version.)
Firefox might be a pretty bad example here. IIRC it was only recently they stopped using the undocumented RUSTC_BOOTSTRAP to enable unstable nightly features in stable Rust.
Oh, I see. I only vaguely remembered some changeset regarding it. I must have been mistaken, then, and it's still in use.
In any case, sneakily using nightly features can make using a different Rust version problematic, since these features are free of any stability guarantees.
packed_simd is accounting for the diff there, and it is still a nightly-only (meaning experimental features) crate, so looks like it's still using that.
What a confusing codebase. https://github.com/mozilla/gecko-dev/tree/d36cf98aa85f24ceef... This package documents a "minimum supported rust version" then goes on to set RUSTC_BOOTSTRAP (cirumventing, enabling experimental features). Very mixed signals - I'm pretty disappointed to see documentation say one thing and then the code do another.
I would suspect the developers are maybe not entirely in tune with the Rust ecosystem, and that would make sense, they have more important stuff to do, like building Firefox, than playing with Rust. :)
They are well aware of what they’re doing. I personally find it extremely unfortunate but, nothing we can really do.
Luckily as far as I know this is the only serious mis-use of the bootstrap flag. This would be a bigger problem if more people misused it. (And it has, in the past, when people used those packages. There was a relatively high-profile Debian situation about it a while back…)
I'm pretty sure all uses of RUSTC_BOOTSTRAP are to get around limitations in Rust's SIMD support.
The main users are encoding_rs which depends on packed_simd and qcms which needs NEON support.
So it's not like we're going around using all sorts of unstable features. It's very targeted and at least in qcms's case unlikely to change before stabilization.
The crate linked to from the comment you replied to uses RUSTC_BOOTSTRAP for a non-SIMD reason: To allow Firefox to be built with somewhat old rustc.
Firefox no longer updates its MSRV in sync with Rust release trains. I’d be happy to remove this particular RUSTC_BOOTSTRAP if we decided to increase Firefox’s MSRV (currently stuck at 1.47.0).
Yeah, Firefox is pretty much the worst example imaginable, because it deliberately depends on unstable (as in, actually unstable, not just de-facto-stable-but-not-yet-formally-stable) features, pretty much guaranteeing that upgrades of the compiler will break things regularly.
Firefox is effectively targeting a nightly compiler, they just use this sneaky underhanded trick to access the features in a stable release.
Hmm. It could be nicer for stability reasons if Firefox pinned a specific nightly compiler rather than using a nominated stable release plus the RUSTC_BOOTSTAP trick. But I can understand why they would prefer the stable release.
Anyway: in short, the premise of this article is incorrect because Firefox cheated.
> No, editions require explicit activation and the "default" edition will remain forever at 2015, i.e. Rust 1.0.
With the slight caveat that this is the "default if not specified", but the default when creating a new project with "cargo new" is to specify the currently latest version on the generated Cargo.toml file.
That is, there are two defaults: the default for pre-edition projects (forever 2015), and the default for creating a new project (sets the project to what was the latest edition when the "cargo new" was run).
I mean you can mix and match dependencies of different editions, and there are (IMHO) very few reasons to start a new project with an old editions. For that (IMHO) very few reasons you tend to be aware of you intentionally wanting to use a old version and as such it's not a problem.
Through I would say there is no real default
rust editions, it's more appropriate to say crates/libraries "keep" the rust edition they
where created with until explicitly changed.
Mainly to fix soundness holes in the language. Like there was some problem with match statements, guards, moving values and potential (I think?) user after free or so. Which required match guards to be slightly constrained in some edge cases.
Editions are more like a language dialect, and all newer compilers support all "older" editions.
What versions change tend to be:
- config defaults, e.g. make some warnings errors, change the default dep. resolver, etc.
- syntax (in minor ways). E.g. add a new keyword for a new feature/syntax or remove a reversed but unused keyword where it's no clear that it's not needed.
- improvements the the borrow checker or import system which in some edge cases could break existing code.
Anyway any rust version supports all editions released up to the point in time and you can freely mix and match them between dependencies.
Rust editions aren't supposed to break old code, the entire point is that unless you modify your Cargo.toml (or the arguments you pass to rustc if you aren't using cargo) then everything keeps working like it did previously.
...any performance measurements from before this transition aren't compatible with those after it, since I'm building different things with a different toolchain.
Yes, but this would have been true even if there had been no rust errors or incompatibilities. You upgraded your rust compiler, so you're no longer comparing like with like.
Unless of course your goal is to benchmark the difference between rust compilers, or maybe between software built with up to date compilers in general.
The author insinuates that the breakage is intentional, but I'm not convinced that it is. For instance, one of the cited issues is that newer cargo versions cannot parse the old Cargo.toml. However, as far back as 2016 cargo was maintaining backwards compatibility when making bug fixes to its TOML parsing. [1]
When Rust 1.0 was released, the stated stability commitment had three documented caveats:
«
We reserve the right to fix compiler bugs, patch safety holes, and change type inference in ways that may occasionally require new type annotations.
»
I definitely had to add type annotations when compiling "old" Rust code with a modern version, but it wasn't a huge deal in practice.
While Rust's handling of backcompat isn't perfect, I think it's very good given how young and fast-moving the language is. I usually have more trouble dealing with old C++ code on newer versions of G++/LLVM than Rust. Admittedly that C++ code often predates the very existence of Rust, but still, you'd expect a higher standard of backward-compatibility from such an old and widespread language.
Rust is just too young and moves to fast to be used for software projects you want other people to be able to compile. In addition to the backwards compatibility problems it suffers even more serious forwards compatibility problems due to the type of dev culture currently associated with it. They always use $latest and what is in $latest changes so fast even if your rustc is 4 months old it already can't compile code written in $latest. If you're only shipping binaries it's okay. And in the future I bet Rust will be pretty nice. But right now it's painful and full of pitfalls.
> Rust is just too young and moves to fast to be used for software projects you want other people to be able to compile.
Except many people doing exactly that and it working fine.
> backwards compatibility problems
Which aren't really a problem in practice. Definitely not worse then in any other language, yes there was some intentional breakage (soundness bug fixes) and unintentional breakage (compiler bugs) but most of this was in the very early stable rust versions since then accidental breakage which isn't caught and fixed before stable has become quite rare. As far as I know rust does more to find accidental breakage then many other languages.
> They always use $latest and what is in $latest changes so fast even if your rustc is 4 months old it already can't compile code written in $latest.
What is the problem with requiring a up-to date build chain? Slow long release cycles with a lot of patch back-porting is a software development model which for many (most?) projects has been deemed to not work well and has been replaced with something more in the direction of CI. Let's be honest even if we assume slow long releases are better for compilers, they still put quite an additional burden one the compiler development process which a is feasible if you have a lot of payed devs from large companies, but not really if only your core devs are payed (by the foundation and/or companies) but a lot of relevant contributions come from people not directly payed to work on rust.
> But right now it's painful and full of pitfalls.
I don't think so, but I guess we both can agree that thinks are improving, for me to make it even better and for you to maybe make it usable for the things you currently treat it as not suited for. ;-)
>What is the problem with requiring a up-to date build chain?
Well, Debian Bullseye, a distro that hasn't even been released yet, already has a rustc that's so out of date (ie, ~5 months, 1.48) that it can't compile code written today using today's features. I guess if you come from the web or some "fast" internet company where you rebuild your entire world every day then 5-6 months is an eternity. But with, say, c++, I can expect to be able to compile C++ programs written by devs for a handful of years before C++?? issues start. And despite Bash 5 getting new features regularly I can expect a bash script written today to work on my 15 year old desktop running linux 2.6. It's not because these languages don't add new backwards incompatible features. It's because the devs don't immediately use them and say, "What is the problem with requiring a up-to date build chain?"
If you only talk to other bleeding edge devs in the rust community I can see how this ethos propagates. But not everyone is a bleeding edge rust dev. Some of us run our distros for many years and just want to compile programs.
Requiring the use of rust-up instead of using system repos is the often suggested way around this. But I, and many others, absolutely hate using third party compiler software from out of repos. It's a bad practice and leads to it's own trouble as shown the very topic this discussion thread is about.
I don't see how that's different to C++. You will run into the same issues there if you happen to use code that uses some of the various new features e.g. items targeted for C++23, that are already starting to be supported by the newest versions of GCC and Clang. If you're on Debian Stable or RHEL, I believe those are even still using GCC versions that don't fully support C++20.
Their argument is a cultural one, not a technical one. Technically, they’re the same, but culturally, C++XY takes time to see adoption, but Rust 1.Y tends to be adopted almost immediately.
On certain corners of Github, I wouldn't say so. I think you would see a lot more people doing the same thing in C++, if there was a Cargo-style package manager that got more adoption there.
It's not a problem of running rust code, you always can run any "latest" compiled rust code with Debian Bullseye. Only for building the binary do you need a up to date version.
But this isn't uncommon for a lot of projects which might require up to date build tools for them to be build.
I my opinion, and I know many do disagree with me, the problem is the idea of pinning dev-tools when releasing a distribution and expecting this to work well. In my experience it doesn't, and it's not limited to rust or web-related things where it doesn't work well.
(Like e.g. I don't know how often I had to install newer versions of clang, gcc, C++-related build tools, python related build tools, system dependencies, java etc.)
> Well, Debian Bullseye, a distro that hasn't even been released yet, already has a rustc that's so out of date (ie, ~5 months, 1.48)
Sadly, Debian does this a lot - Bullseye is going to release with NodeJS v12 which is already in Maintenance LTS (dying) and not the Active LTS (v14) and has 4 more newer Current releases (15->18). I am a Debian supporter but this is a distro problem of locking in on already out of date dev tools over and over again, Bullseye is already far out of date before it's even launched.
> Well, Debian Bullseye, a distro that hasn't even been released yet, already has a rustc that's so out of date (ie, ~5 months, 1.48) that it can't compile code written today using today's features.
This sounds more like an argument against Debian’s packaging practices than Rust. Debian is full of out-of-date tools, and that and CentOS doing the same are the reason non-system package managers are so popular.
Depending on what you consider “mature”, sure. Here is a short list of programming languages where I have had to install an up-to-date version on recent Debian, Ubuntu or RHEL derivatives in just the last month:
- Node.js
- Python
- Go
- Rust
- C++
- .NET Core
- Java
None had an up-to-date version in the distribution repositories. It’s a problem - and for those who defend it as otherwise while lamenting the rise of Docker, perhaps it’s worth some careful introspection about what a majority of people actually want from an operating system distribution, and whether the concept is in fact a relic of the days when software was distributed on CDs via the mail.
Really? For what reason did you have to install a newer Python, a newer C++ compiler, or a newer Java runtime?
> None had an up-to-date version in the distribution repositories.
Of course not. A Debian release is meant to not change – except for security fixes – for the duration of its 2 year cycle. That's a feature, not a bug.
> This is what Debian's Stable name means: that, once released, the operating system remains relatively unchanging over time. [1]
If you just want to compile programs, perhaps a distro + release channel geared towards production server deployments isn't the best choice. They even call out that fact in the "Why Debian" page:
> You can fine-tune the degree of risk you want to take, since Debian has three separate releases: Stable, Testing, and Unstable. On some of our machines (the server, the kiosk machines) we run 'stable'. Some of the other systems (individual work-stations) run various combinations of testing/unstable. (Note that there are no security updates for testing). I run some stuff from experimental on my own work-station. What's great is the ability to make finely graded decisions for different machines serving different functions. But even the more adventurous choices are solid enough that they virtually never break. And `stable' just never breaks ;-). [2]
I used Rust at FullStory for years and the pain you describe just didn't really exist, except when I wanted to test out the latest-and-greatest features that were usually better to wait until they baked on stable.
The only real pain we felt was around iOS bitcode and that was mainly Apple's fault because they make the whole process so Byzantine if you aren't using clang.
Well of course a hello world Rust project would just compile fine since Rust 1.0, unlike my recent Rust project which broke again and that just broke on a minor version bump.
As for another ancient Rust project which was also on 1.0 when I was trying the language out, the borrow checker on 1.52.1 screeched at every line of my code.
While C++ is just as bad, the fact that Firefox must always use the latest Rust compiler gives you a hint that it will not work on lower versions; hence the need of a MSRV. (Minimum Supported Rust Version)
If the borrow checker of 1.52.1 "screeches" on every LOC but it compiles on 1.0 then very likely either there's some bug in 1.52.1 that you should report or you code was never correct and should never have compiled in 1.0 in the first place but did due to a compiler bug that since got fixed.
Of course, without more info nobody can tell which of these or even whether it is one of these two or something else.
OK, I'll say it because nobody else seems to want to: the sensible approach would be to ask for some help on one of the several official avenues that are open to you: users.rust-lang.org to begin with, and then the Discord (if you're comfortable with Discord). Aside from the high quality of help available to anyone, of any proficiency level, there's a pretty good chance you can describe your problem to someone who worked on Rust in Firefox.
But why bother with that when you can write passive-aggressive blog posts that are devoid of useful information about the errors that were encountered instead.
Firefox has explicitly used unstable Rust features for years. Their build system opts into this behavior knowing these features are not guaranteed to be stable in future versions. It's 100% unsurprising that using unstable features means your code might break with a future compiler.
The backwards compatibility guarantee of Rust applies only to stable releases. Firefox is weird in that it is enabling nightly features in an unnoficial compiler build that, for some odd reason, they want to tag as "stable". But it isn't.
Technically I believe that they're using the official compiler build, just using an unsupported and undocumented backdoor to enable nightly features in that official stable build.
Well, it would be nice to start with verifying whether or not a compatibility promise was actually broken... as it stands we don't really have enough information to know (short of spending time trying to reproduce OPs build environment ourselves), but as you can see by the comments here the general evidence points towards not.
So you're claiming that needing help to fix an issue in a language you don't at all know is bad? How is it supposed to work otherwise? In my opinion, the fact that you have an option of asking an expert in this situation is a good thing.
I don't want my tools to break from under me, and I don't want to be forced to call tech support needlessly. Do you love dealing with refrigerator repairs? Why should we love dealing with Rust repairs?
It's not needless if you've found an actual bug, i.e. if your refrigerator is actually broken. I too wish it was possible to get a refrigerator that never breaks or malfunctions or needs to be replaced. If you know how to make one of those, please start selling it, you'll probably get very rich.
Experiencing backwards compatibility breakages is not "finding a bug" it is the tool being broken from under you.
I don't have to prepare for the possibility of having live tech support open whenever I update the Go binary in my projects. Rust advocates should not try to suggest this is reasonable.
If you use highly unstable, nightly only, Rust features then experiencing breakage is almost a certainty. That's why they're highly unstable, nightly only, features.
A software bug is an error, flaw or fault in a computer program or system that causes it to produce an incorrect or unexpected result, or to behave in unintended ways.
If the Rust compiler developers intend to provide backwards compatibility, but accidentally make a change that breaks that, then that is absolutely 100% a bug. You are allowed to prefer that the software you use has minimal bugs, but you are deluding yourself if you think that the Go compiler (or essentially any other piece of software) is bug free.
What? If you run into a bug, having people willing to help you out is absolutely a feature and to insinuate otherwise is absolutely ridiculous. If you personally prefer to deal with it on your own, then you're still free to do so.
Keep in mind, that Rust backwards compatibility don't extend to some cases. If an unsoundness error happens, future versions WILL break backwards compatibility.
This whole thread desperately needs more information about the actual error. Firefox doesn't use stable Rust (it enables experimental features), so from my viewpoint there is no bug here until more facts are on the table.
It also does not extend to unstable features, which Firefox (the program in question) uses. The whole post is quite ill conceived and makes me reconsider my general trust in the authors' output.
> But they never made this complaint in the actual Bugzilla where someone could consider their feedback, they skipped straight to the "complain via blog post" phase. [...] My advice to the author is that perhaps they should extend a little more charity and "just ask" first, before they jump at the opportunity to complain in public - without having mentioned the issue to anyone with the ability to fix it.
Which comment links in turn to another post, for which the blogger writes,
> I would file a bug report but I cannot imagine that Fedora would accept it. They already know that this feature doesn't work; it's right there in the DKMS manpage. It's there anyway because, well, I don't know. This is the most user-hostile decision I think I've ever seen Fedora make.
but in fact the issue was fixed within a week of reporting it.
Firefox, in particular, uses the not-so-secret escape switch to unlock Rust nightly features on Rust stable. A bunch of folks on the Rust team are pretty unhappy about this (see e.g. https://github.com/rust-lang/cargo/issues/6627), but it is the current situation. So "Firefox broke after I ran rustup" is a very different complaint from "My code, on Rust stable, without the secret escape switch broke after I ran rustup," and the blame (if there is any blame at all, which is unclear without the actual error report) is on the Firefox developers, not the Rust developers.
In the general case, the Rust folks care a lot about backwards compatibility, but in turn they do that with an eye towards never having a Rust 2.0. They've taken a lot of innovative steps towards making Rust 1.x usable indefinitely, including the nightly/unstable system, the epoch system, crater, etc. A consequence of staying on Rust 1.x indefinitely is that you cannot possibly be bug-for-bug compatible with Rust 1.0 and Cargo 1.0 for all theoretically possible code (see Hyrum's Law: https://www.hyrumslaw.com/). However, if something breaks in the real world, report it, and I expect the Rust developers will be sympathetic and try to fix it. Without any indication of what broke, nobody can do anything with this post except get unactionably mad at other people, and that's pretty useless for actually getting things done.
The author is, of course, free to blog whatever he likes. But I think the HN community should stop upvoting his clickbait posts.
The only additional detail I could find from the author’s Twitter thread on the topic:
> In this case it looks like something in a Cargo.toml in Firefox wasn't to the taste of the newer version of Cargo. Presumably it was valid back then but not any more.
Sounds like if this really is a failure of backwards compatibility, it is a failure of such for Cargo, not Rust. Does Cargo have the same backward compatibility goals as Rust itself?
It generally does, yes. Without more details, it is really hard to say what actually happened. I'm not aware of any breaking changes to the Cargo.toml format, though maybe I missed something.
They may have also meant "a new dependency version broke", not literally that Cargo couldn't understand Cargo.toml. Need more details.
The same is true for Dlang. Go on D's IRC channel and you can talk to core compiler authors who will help you find a solution to any problem in ~10 minutes.
My experience with this "high quality help" was usually bunch of less experienced people telling me how I'm doing things wrong and how Rust cannot possible lack a feature or need improvement. And that was after making triple sure that my conversation would not be combative or try to sound entitled.
Sadly there is some cult around the whole community... although I find the core developers to be pretty great.
Similar things happen in a lot of other languages, sometimes it is not even a matter of a changing/evolving spec. (like TypeScript, or any other language that improves type checking or compile/interpretation validations at each minor version - breaking old code because it no longer type-checks/validates).
Sometimes I feel that C is the only language that can benefit from compound gains over time, their spec is tight and sees sparse nuanced improvements in wide intervals of time.
This is actually not a problem of spec but one of:
- firefox "secretly" relying on unstable things while using stable rust (using some magical undocumented rust flags meant to be only used for bootstrapping rust).
- the older firefox release relying/touching on some "bug" in rust which was fixed (e.g. accidentally accepting malformed config files, or soundness issues).
- a bug in the compiler no one put resources to fix in yet (as e.g. close to no one is affected by it and there are more relevant bugs to work on).
This can happen to you in C or C++, too.
For any larger and more complicated projects some bugs "popping out" when using newer compilers due to either compiler bugs or code bugs "somehow passing by" in earlier compiler versions is totally a thing.
Through due to how long the C standard stood still it's not that often happening in C, I guess? Hm, I wonder if Linux kernel devs might disagree??
The Linux build regularly breaks on new Clang versions. GCC is better in this regard, but we still have issues. The most common ones (that I’ve noticed, anyway) are codegen related — Linux makes assumptions about gcc’s output that break, even if gcc continues to accept the source code.
> Through due to how long the C standard stood still it's not that often happening in C, I guess?
Back in the GCC 4 timeframe (~2005), the compiler started taking a more strict view of the C standard in a way that produced additional warnings/errors relative to the GCC 3.x series. Compiler upgrades do regularly break some subset of packages in distro repositories; breaking C++ happens a lot more than C, but it happens.
One thing I ran into when I was trying to compile something after it wasn’t touched for a year or so is that cargo doesn’t in-fact look at its lock file what minor versions is concerned.
This caused cargo to install different minor versions than it would have a year ago despite a lock file being present.
These minor version updates were relying on newer rust version features and then failed to build on the old version of the rust compiler I was using.
Updating rust made the build work again, but now with additional warnings (where the code I was compiling did shady things which old rust wouldn’t detect but new one did), but it did finally produce a usable binary.
Still, I was a bit miffed by cargos behavior of ignoring minor versions locks in the lock file and installing later versions than what was locked.
What good is a package lock file if it isn’t respected?
I think I’ve noticed that cargo install would pick up newer semver-compatible versions than what was in the lockfile unless I passed —-locked explicitly, which seemed surprising to me.
It sounds little bit like the (known) situation around cargo where it doesn't default to `--locked` and so results in surprising behaviour for many people.
Oh, or, I guess, it might be how the version is specified--guess we need some more details on what "compile something after it wasn’t touched for a year" entailed.
Since rust does a "crater run" with each release, where it builds (all?) many known crates, it has stats with how many break. I vaguely remember a comment by Steve Klabnik here in HN one time (which I sadly cannot find now) that said over the course of a year, something like 95% of unupdated crates compile still compile on the newest version.
I think that's pretty good, especially for such a young language with some ongoing significant changes. And I think that's stable enough for a production environment where there's an expectation of minimal ongoing maintenance. It means you rarely have to touch your code through updates, but occasionally will need to tweak something.
But it does add up, and something 5 years old is decently likely to not compile. I personally ran into something like that digging up an old project, and the problem is it's hard to incrementally fix it, since at that point all the dependencies are quite old, too. And there's a complex relationship between the dependencies snapshotted at that moment, and so probably you can just update them all to the very newest version and they'll be compatible, but somewhere in the middle is hard.
just checked: the first Go code i ever wrote, over 8 years ago, still compiles flawlessly. obviously the world is filled with trade-offs, but my oh my is it nice to use a language that doesn't break old code.
I'm not sure you can compare the code base of you first program in Go, that is probably small and straightforward, with something as huge and complex as Firefox.
Have you ever seen a big codebase build 100% of the time after arbitrary toolchain, env, deps upgrade?
There are some project more focused on that but even them eventually give up on supporting all versions of their deps. Likewise for compilers, pretty much regardless of the language. I mean the only way to stay perfectly compatible with random codebase is to keep the compiler even bug compatible with older ones, which is not particularly interesting...
gcc seems to not always be backward compatible in practice. clang too. msvc too.
Users (and this is what the blog's author is here, they aren't developing Firefox they just want a benchmark activity) aren't very interested in solving technical problems and so, as seen here, they won't tell you what the error was. They definitely won't admit to any suspicion that it's in any way their fault. It's your fault.
From their perspective, who cares what the error is? They formed an intent, and then your stupid computer software instead of fulfilling their intent did something else. This is your fault.
For example maybe I wanted to delete the old data, and I typed "rm new-data". Don't tell me that deletes the new data, I can see that now, it's your fault that the new data is deleted, I wanted to delete the old data.
For a UX point of view, where possible try to offer "Undo". The user doesn't care that shooting themselves in the face was a bad idea, and they definitely don't care that you made them click "Yes, really, in my face, I understand this will hurt" three times first, now that they've done it, and it hurts, they want to undo it. Adding a forth confirmation step will not reduce the complaints.
Sometimes it will be hard to "undo". But you should periodically revisit decisions about that over the lifetime of a piece of software as resources increase. If you have 64KB bytes of RAM it's understandable if I can't undo "fill circle" in v1 of your Freeware art program. It's much less understandable in version 16 of the $100 program on a 16GB PC...
Would it make sense to be able to "undo" a Rustup even though that's difficult? Maybe. It's worth at least considering.
And yes, it is nice that Rust has a helpful community who might try to help you fix problems if you explain what the problem is, but this isn't really about Rust, it's about Users.
An "undo" in Rustup barely makes sense, because it is almost virtually a stateless thing. However, maybe in this case, it would have; the author hasn't provided enough detail to truly say.
But in that case they're Firefox "users", not Rust users. This distinction matters because the use of Rust is just a technical detail which ultimately the user doesn't really care about. They're benchmarking Firefox, not Rust.
Therefore the onus is on Firefox to provide a good user experience.
Firefox is for browsing the web and rust is for writing software. Neither is for stress testing or benchmarking the users computer. That would be like arguing that your thermos manufacturer is responsible for providing a good experience to the user using it to hammer nails.
What you are saying is true in the Hyrum's Law (https://www.hyrumslaw.com/) sense, but should not be true for a mature programming language which maintains backward compatibility.
The question then is how does someone define backward compatibility?
The answer is a formal definition of what the expected behaviors and expectations of the programming language in question. This usually means a language specification or extensive unit tests that effectively define what the programming language should or should not do for a given set of circumstances.
Rust already does this, they have extensive testing of new releases via e.g. crater. "Run the new compiler on every public piece of code possible" is actually a very unsurprising strategy these days and communities beyond Rust use this tactic, and this is all on top of the probably ~thousands of unit tests in their suite (not that users go looking at unit tests to decide what's "valid" Rust or not.)
As someone who's invested a lot of time in PLT and even at one point had their name on a draft of the Haskell standard, the unfortunate reality is that language specifications are very often not useful to the wide majority of people, while being quite laborious to produce and maintain and work with over time. The culture of computer programming, at large, is part of this, it's not some mathematical fact, but a social one. At the end of the day, what constitutes "Rust the language" in any formal capacity doesn't matter; "Rust the language" is a social construct in that sense, a guarantee Rust will still be Rust even if some minor bugs are fixed that they let slip by. This is how most people think of it, when you get down to the nitty gritty.
I'll also say that tons of regressions happen in mature languages with backwards compatibility. Ask any Linux distro maintainer! I don't even keep track of all the weird reasons regressions happen anymore; it's like counting sand on a beach. It's not a happy fact of life, but it is what it is, and regressions do happen, no matter if your language is stable for 5 years or 50.
>> the unfortunate reality is that language specifications are very often not useful to the wide majority of people, while being quite laborious to produce and maintain and work with over time. The culture of computer programming, at large, is part of this, it's not some mathematical fact, but a social one. At the end of the day, what constitutes "Rust the language" in any formal capacity doesn't matter; "Rust the language" is a social construct in that sense, a guarantee Rust will still be Rust even if some minor bugs are fixed that they let slip by. This is how most people think of it, when you get down to the nitty gritty.
What you are describing is the less fun and sometimes tedious nature of software maintenance.
It can be thankless work, but it is very important work to ensure that a programming language is reliable and to minimize the regressions that sometimes occur.
It is very much a social contract, but essential so that expectations are met, particularly for systems programming that Rust targets.
I wonder if anyone has ever tried to create a literate programming-style specification for programming languages--something that combines the high-level descriptions of programming language semantics with executable unit tests. Such a system would provide detailed semantics and give programming language creators and maintainers a good way to prevent regressions and create RFC branches to try out and test new ideas. It would help to bring the social constructs of the programming language closer to the technical implementation semantics.
Like Ada, C++ is standardised by ISO. With I suspect much the same consequence, ie there is a big gap between the ambition of the language's most important architects and what they can persuade the committee to sign off on for the standard.
It is informative for example to review talks Bjarne gave about C++ Concepts in 2015 compared to the C++ 20 feature Concepts. That's five years to get something similar in scope into the actual language standard, and of course since this isn't exactly what Bjarne designed, you then to have transition compilers and codebases to the actual standard feature...
I'm dubious about the value of conformance testing as a deliberate exercise. In practice real world implementations will definitely be defective and it's important that defects are cured when identified, mostly by changing implementations but sometimes in reality by changing the specification to reflect what is implemented. But I don't know how much value I believe there is in somebody sitting down to try to construct a test suite starting from the standards documents, rather than gathering minimal samples of real world code that did not do what the standard says it should do so that implementations can check they get those right (and where appropriate the standards body can reconsider whether the standard itself is wrong here). It appears to me that ACATS tries to do the former, right?
> Ferrocene is a sustainable effort led by Critical Section GmbH, a newly formed Ferrous Systems subsidiary, tasked with making Rust a first-class language for mission and safety-critical systems. Ferrocene produces a qualified Rust compiler toolchain. General availability is expected by the end of 2022.
And also:
> Ferrocene is a vehicle for a versioned Rust and MIR specification, paired with automated verification of Rust semantics. These "runnable specs" give developers in mission-critical and high-security environments a sound, proven, and addressable foundation for building critical libraries, analysis tools, and further system assurances.
And also:
> Critical Section will maintain designated legacy versions of the Rust toolchain and supporting utilities. This support includes backporting fixes of critical language and standard library issues (performance bugs, unsoundness, security) and maintaining key rustc targets, including test cases and platform-specific testing.
And finally:
> Ferrocene is a principled project with much work ahead, requiring cross-industry collaboration and continuous feedback. It has support from crucial industry partners and subject experts, and we're building a thoughtful community.
> Right now, Ferrous Systems and Critical Section are calling for additional partners to join this effort. We're currently looking for partners from diverse industries
The Rust apologists are numerous in these threads. Several people have told OP he should have reached out to ask the Rust community for help rather than writing a “passive aggressive” blog post. Is pointing out an undesirable behavior of Rust passive aggressive?
I had the same experience trying to use older versions of Rust or trying to use newer versions of rustc on older crates. It doesn’t “just” work. For many of us this coming from Go, this seems like a step backwards.
I’m thankful OP had the courage to post this note about his experience. I’m also disappointed to see members of the Rust community to suggest its a failing on OP’s part that they were not able to get Firefox to build and that bringing up this difficulty is something OP was wrong to do.
He wrote a blog post about a language and tools that he doesn't personally use or understand that he was trying to use to stress test his system. From reading the responses it seems that he may have misunderstood Firefox specific issues as being rust issues by virtue of having insufficient understanding to disambiguate. Had he communicated he probably would have been able to derive this understanding easier from conversation thus the exhortation that he ought to have do so sees to be productive and correct.
I don't think its apt to call the people critiquing the critique "apologists" when the entire original blog post seems to be misunderstanding on the part of the blogger. Posts that critique things the poster do not understand tend to themselves generate critical feedback which seems fairly measured to me.
> I had the same experience trying to use older versions of Rust or trying to use newer versions of rustc on older crates. It doesn’t “just” work. For many of us this coming from Go, this seems like a step backwards.
I have read the blogpost... and this isn't really the substance of the complaint? It is Mozilla's fault really to be honest, they should be sticking to a nightly if they want to use weird and non-standard features.
I personally think the only similarly between yours and the authors' is the (supposed) unmet promises of backwards compatibility - guess what, I code in different languages (including Go) and I can see breakages regularly, mostly not due to breaking a "backwards compatible" promise but because the broken code has been always there, just not being enforced by the compiler. Specifically in Rust, the backwards compatibility promise wasn't Microsoft's "everything including undocumented features" backwards compatibility: it was only limited to documented features used properly. This can surprise people who relies on the Microsoft definition of backwards compatibility.
OP could have easily found out why FF failed to build on newer Rust, which is in fact due to its use of experimental/unstable features which it enables through a flag that is only supposed to be used for bootstrapping Rust. Because it effectively opts out of any stability guarantee, FF only builds on certain Rust versions.
But instead of taking a moment to read and understand the error messages, or ask the community for help with understanding them, OP chose to publish and popularise a blog post without including the error messages (or any context that would help anyone to make up their own mind based on actual facts).
120 comments
[ 4.1 ms ] story [ 197 ms ] threadIf, on the other hand, the code was correct, then backwards compatibility is definitely expected. The same holds for the format of the cargo files, btw. changing something like this during one major (or minor, depending on the release cycle) release is bad form IMO.
The mentioned case of C compilers and their warnings is an interesting grey area. Presumably it would still compile just fine, but as a developer you want -Werror and -Wall. In practice this often makes certain libraries incompatible after a compiler upgrade.
This included:
- Soundness issues around Self: Sized bound requirements and traits. (Big breakage bout early one in rust lifetime.)
- Soundness issues around something related to match statements and guards I don't remember.
- Something related to accepting invalid inputs, I think this included Cargo accepting invalid Cargo.toml files.
There was also a very small bit of accidental breakage which counted as a bug but affected close to no one so no one ever invested time to fix. For example a bug which only affects people running multiple tightly linked rust crates on older editions and doing unusual stuff wrt. macro imports and re-exports which where only valid for I think 1-2 rust version.
Then there was a bit of accidental stabilization, where things which should not be doable on stable where doable. If not found very early this was normally kept stable if possible, but I think there was at least one time where this "stabilization bug" needed to be fixed.
Anyway to cut it short:
1) Compilers are not perfect, this is also true for C/C++.
2) At least serve bugs (e.g. soundness bugs) are not treated as "de-facto" standardized/stabilized but are fixed (something I prefer).
----
As a side note Firefox is a bad example as they used some tricks to use some definitely not stable options on stable rust which is basically guaranteed to cause breakage at some point and not covered by any stability guarantees.
As another side note `#[deny(warnings)]` is also not covered by stability guarantees, the compiler is free to add new warnings any time (but will do so with a lot of care, e.g. preferably only with new rust editions, which also may make some warnings errors).
---
Also:
-`rustup` supports setting overrides, no reason to fear updates, just pin a older rust version in your create using overrides (if you need to).
- Idk. about his problems but I have yet to see a case where any breakage wasn't reasonable straight forward to fix (weather unintentional, intentional to fix soundness or due to an edition change triggered by me).
Tons of regressions like this happen all the time in the GCC/LLVM world. Every time we do a bump of the default C compiler, you can bet it will take 4-8 weeks while regressions -- from "This random thing enabled -Werror, again" to "Someone used a new feature but scoped the #ifdef wrong" to "Actual segfaults in libstdc++" -- are sorted out.
Which is fine for Firefox itself.
Just a problem for anyone forking of Firefox. (Or for other reasons trying to build it with a different rust version.)
https://github.com/mozilla/gecko-dev/search?q=RUSTC_BOOTSTRA...
Specific example: https://github.com/mozilla/gecko-dev/blob/d36cf98aa85f24ceef...
In any case, sneakily using nightly features can make using a different Rust version problematic, since these features are free of any stability guarantees.
Arch Linux carries a rather large patch updating some vendored dependency in order to make Firefox 78 compile with a newer Rust. https://github.com/archlinux/svntogit-packages/tree/packages...
I would suspect the developers are maybe not entirely in tune with the Rust ecosystem, and that would make sense, they have more important stuff to do, like building Firefox, than playing with Rust. :)
Luckily as far as I know this is the only serious mis-use of the bootstrap flag. This would be a bigger problem if more people misused it. (And it has, in the past, when people used those packages. There was a relatively high-profile Debian situation about it a while back…)
The main users are encoding_rs which depends on packed_simd and qcms which needs NEON support.
So it's not like we're going around using all sorts of unstable features. It's very targeted and at least in qcms's case unlikely to change before stabilization.
Firefox no longer updates its MSRV in sync with Rust release trains. I’d be happy to remove this particular RUSTC_BOOTSTRAP if we decided to increase Firefox’s MSRV (currently stuck at 1.47.0).
Firefox is effectively targeting a nightly compiler, they just use this sneaky underhanded trick to access the features in a stable release.
Hmm. It could be nicer for stability reasons if Firefox pinned a specific nightly compiler rather than using a nominated stable release plus the RUSTC_BOOTSTAP trick. But I can understand why they would prefer the stable release.
Anyway: in short, the premise of this article is incorrect because Firefox cheated.
This is in contrast to C and C++ compilers like GCC and Clang, where the default "std" setting is often updated with new releases.
With the slight caveat that this is the "default if not specified", but the default when creating a new project with "cargo new" is to specify the currently latest version on the generated Cargo.toml file.
That is, there are two defaults: the default for pre-edition projects (forever 2015), and the default for creating a new project (sets the project to what was the latest edition when the "cargo new" was run).
I mean you can mix and match dependencies of different editions, and there are (IMHO) very few reasons to start a new project with an old editions. For that (IMHO) very few reasons you tend to be aware of you intentionally wanting to use a old version and as such it's not a problem.
Through I would say there is no real default rust editions, it's more appropriate to say crates/libraries "keep" the rust edition they where created with until explicitly changed.
Mainly to fix soundness holes in the language. Like there was some problem with match statements, guards, moving values and potential (I think?) user after free or so. Which required match guards to be slightly constrained in some edge cases.
Version: 1.0.0,.., 1.50.0, 1.51.0, ... Edition: 2015, 2018, ..
Versions are the compiler version you use.
Editions are more like a language dialect, and all newer compilers support all "older" editions.
What versions change tend to be:
- config defaults, e.g. make some warnings errors, change the default dep. resolver, etc.
- syntax (in minor ways). E.g. add a new keyword for a new feature/syntax or remove a reversed but unused keyword where it's no clear that it's not needed.
- improvements the the borrow checker or import system which in some edge cases could break existing code.
Anyway any rust version supports all editions released up to the point in time and you can freely mix and match them between dependencies.
Yes, but this would have been true even if there had been no rust errors or incompatibilities. You upgraded your rust compiler, so you're no longer comparing like with like.
[1]: https://github.com/rust-lang/cargo/pull/2680
The author seems to do this a lot.
https://news.ycombinator.com/item?id=27385818
« We reserve the right to fix compiler bugs, patch safety holes, and change type inference in ways that may occasionally require new type annotations. »
See https://blog.rust-lang.org/2014/10/30/Stability.html
While Rust's handling of backcompat isn't perfect, I think it's very good given how young and fast-moving the language is. I usually have more trouble dealing with old C++ code on newer versions of G++/LLVM than Rust. Admittedly that C++ code often predates the very existence of Rust, but still, you'd expect a higher standard of backward-compatibility from such an old and widespread language.
Except many people doing exactly that and it working fine.
> backwards compatibility problems
Which aren't really a problem in practice. Definitely not worse then in any other language, yes there was some intentional breakage (soundness bug fixes) and unintentional breakage (compiler bugs) but most of this was in the very early stable rust versions since then accidental breakage which isn't caught and fixed before stable has become quite rare. As far as I know rust does more to find accidental breakage then many other languages.
> They always use $latest and what is in $latest changes so fast even if your rustc is 4 months old it already can't compile code written in $latest.
What is the problem with requiring a up-to date build chain? Slow long release cycles with a lot of patch back-porting is a software development model which for many (most?) projects has been deemed to not work well and has been replaced with something more in the direction of CI. Let's be honest even if we assume slow long releases are better for compilers, they still put quite an additional burden one the compiler development process which a is feasible if you have a lot of payed devs from large companies, but not really if only your core devs are payed (by the foundation and/or companies) but a lot of relevant contributions come from people not directly payed to work on rust.
> But right now it's painful and full of pitfalls.
I don't think so, but I guess we both can agree that thinks are improving, for me to make it even better and for you to maybe make it usable for the things you currently treat it as not suited for. ;-)
Well, Debian Bullseye, a distro that hasn't even been released yet, already has a rustc that's so out of date (ie, ~5 months, 1.48) that it can't compile code written today using today's features. I guess if you come from the web or some "fast" internet company where you rebuild your entire world every day then 5-6 months is an eternity. But with, say, c++, I can expect to be able to compile C++ programs written by devs for a handful of years before C++?? issues start. And despite Bash 5 getting new features regularly I can expect a bash script written today to work on my 15 year old desktop running linux 2.6. It's not because these languages don't add new backwards incompatible features. It's because the devs don't immediately use them and say, "What is the problem with requiring a up-to date build chain?"
If you only talk to other bleeding edge devs in the rust community I can see how this ethos propagates. But not everyone is a bleeding edge rust dev. Some of us run our distros for many years and just want to compile programs.
Requiring the use of rust-up instead of using system repos is the often suggested way around this. But I, and many others, absolutely hate using third party compiler software from out of repos. It's a bad practice and leads to it's own trouble as shown the very topic this discussion thread is about.
It's not a problem of running rust code, you always can run any "latest" compiled rust code with Debian Bullseye. Only for building the binary do you need a up to date version.
But this isn't uncommon for a lot of projects which might require up to date build tools for them to be build.
I my opinion, and I know many do disagree with me, the problem is the idea of pinning dev-tools when releasing a distribution and expecting this to work well. In my experience it doesn't, and it's not limited to rust or web-related things where it doesn't work well.
(Like e.g. I don't know how often I had to install newer versions of clang, gcc, C++-related build tools, python related build tools, system dependencies, java etc.)
Sadly, Debian does this a lot - Bullseye is going to release with NodeJS v12 which is already in Maintenance LTS (dying) and not the Active LTS (v14) and has 4 more newer Current releases (15->18). I am a Debian supporter but this is a distro problem of locking in on already out of date dev tools over and over again, Bullseye is already far out of date before it's even launched.
https://packages.debian.org/search?keywords=nodejs&searchon=...
https://nodejs.org/en/about/releases/
This sounds more like an argument against Debian’s packaging practices than Rust. Debian is full of out-of-date tools, and that and CentOS doing the same are the reason non-system package managers are so popular.
- Node.js
- Python
- Go
- Rust
- C++
- .NET Core
- Java
None had an up-to-date version in the distribution repositories. It’s a problem - and for those who defend it as otherwise while lamenting the rise of Docker, perhaps it’s worth some careful introspection about what a majority of people actually want from an operating system distribution, and whether the concept is in fact a relic of the days when software was distributed on CDs via the mail.
> None had an up-to-date version in the distribution repositories.
Of course not. A Debian release is meant to not change – except for security fixes – for the duration of its 2 year cycle. That's a feature, not a bug.
Operating systems are servant of their applications, not vice versa.
> This is what Debian's Stable name means: that, once released, the operating system remains relatively unchanging over time. [1]
If you just want to compile programs, perhaps a distro + release channel geared towards production server deployments isn't the best choice. They even call out that fact in the "Why Debian" page:
> You can fine-tune the degree of risk you want to take, since Debian has three separate releases: Stable, Testing, and Unstable. On some of our machines (the server, the kiosk machines) we run 'stable'. Some of the other systems (individual work-stations) run various combinations of testing/unstable. (Note that there are no security updates for testing). I run some stuff from experimental on my own work-station. What's great is the ability to make finely graded decisions for different machines serving different functions. But even the more adventurous choices are solid enough that they virtually never break. And `stable' just never breaks ;-). [2]
[1] https://wiki.debian.org/DebianStability
[2] https://wiki.debian.org/WhyDebian#Why_Linux.3F_Why_Debian.3F
The only real pain we felt was around iOS bitcode and that was mainly Apple's fault because they make the whole process so Byzantine if you aren't using clang.
My Rust 1.0 code on the other hand has compiled just fine since the dawn of stable rust.
The only really stable languages might be C89, C99, some fortran, and Cobol.
I think the Rust team does a fantastic job of supporting old code bases with new compilers. Crater is a testament to how much they care in fact.
As for another ancient Rust project which was also on 1.0 when I was trying the language out, the borrow checker on 1.52.1 screeched at every line of my code.
While C++ is just as bad, the fact that Firefox must always use the latest Rust compiler gives you a hint that it will not work on lower versions; hence the need of a MSRV. (Minimum Supported Rust Version)
Of course, without more info nobody can tell which of these or even whether it is one of these two or something else.
But why bother with that when you can write passive-aggressive blog posts that are devoid of useful information about the errors that were encountered instead.
You don't even have to be affecred by it on any of your programs to want to point it out and criticize it...
Rust does not claim perfect backwards compatibility. For instance, unstable features have no backwards compatibility promise.
I don't have to prepare for the possibility of having live tech support open whenever I update the Go binary in my projects. Rust advocates should not try to suggest this is reasonable.
If the Rust compiler developers intend to provide backwards compatibility, but accidentally make a change that breaks that, then that is absolutely 100% a bug. You are allowed to prefer that the software you use has minimal bugs, but you are deluding yourself if you think that the Go compiler (or essentially any other piece of software) is bug free.
Perhaps that makes this a Firefox bug, but given Firefox's historical relationship with Rust, that's not a good look for the Rust community either.
> But they never made this complaint in the actual Bugzilla where someone could consider their feedback, they skipped straight to the "complain via blog post" phase. [...] My advice to the author is that perhaps they should extend a little more charity and "just ask" first, before they jump at the opportunity to complain in public - without having mentioned the issue to anyone with the ability to fix it.
Which comment links in turn to another post, for which the blogger writes,
> I would file a bug report but I cannot imagine that Fedora would accept it. They already know that this feature doesn't work; it's right there in the DKMS manpage. It's there anyway because, well, I don't know. This is the most user-hostile decision I think I've ever seen Fedora make.
but in fact the issue was fixed within a week of reporting it.
Firefox, in particular, uses the not-so-secret escape switch to unlock Rust nightly features on Rust stable. A bunch of folks on the Rust team are pretty unhappy about this (see e.g. https://github.com/rust-lang/cargo/issues/6627), but it is the current situation. So "Firefox broke after I ran rustup" is a very different complaint from "My code, on Rust stable, without the secret escape switch broke after I ran rustup," and the blame (if there is any blame at all, which is unclear without the actual error report) is on the Firefox developers, not the Rust developers.
In the general case, the Rust folks care a lot about backwards compatibility, but in turn they do that with an eye towards never having a Rust 2.0. They've taken a lot of innovative steps towards making Rust 1.x usable indefinitely, including the nightly/unstable system, the epoch system, crater, etc. A consequence of staying on Rust 1.x indefinitely is that you cannot possibly be bug-for-bug compatible with Rust 1.0 and Cargo 1.0 for all theoretically possible code (see Hyrum's Law: https://www.hyrumslaw.com/). However, if something breaks in the real world, report it, and I expect the Rust developers will be sympathetic and try to fix it. Without any indication of what broke, nobody can do anything with this post except get unactionably mad at other people, and that's pretty useless for actually getting things done.
The author is, of course, free to blog whatever he likes. But I think the HN community should stop upvoting his clickbait posts.
> In this case it looks like something in a Cargo.toml in Firefox wasn't to the taste of the newer version of Cargo. Presumably it was valid back then but not any more.
https://twitter.com/thatcks/status/1379506374049140742
i am immediately annoyed by the author using this rhetorical flourish
They may have also meant "a new dependency version broke", not literally that Cargo couldn't understand Cargo.toml. Need more details.
Sadly there is some cult around the whole community... although I find the core developers to be pretty great.
Sometimes I feel that C is the only language that can benefit from compound gains over time, their spec is tight and sees sparse nuanced improvements in wide intervals of time.
- firefox "secretly" relying on unstable things while using stable rust (using some magical undocumented rust flags meant to be only used for bootstrapping rust).
- the older firefox release relying/touching on some "bug" in rust which was fixed (e.g. accidentally accepting malformed config files, or soundness issues).
- a bug in the compiler no one put resources to fix in yet (as e.g. close to no one is affected by it and there are more relevant bugs to work on).
This can happen to you in C or C++, too.
For any larger and more complicated projects some bugs "popping out" when using newer compilers due to either compiler bugs or code bugs "somehow passing by" in earlier compiler versions is totally a thing.
Through due to how long the C standard stood still it's not that often happening in C, I guess? Hm, I wonder if Linux kernel devs might disagree??
Back in the GCC 4 timeframe (~2005), the compiler started taking a more strict view of the C standard in a way that produced additional warnings/errors relative to the GCC 3.x series. Compiler upgrades do regularly break some subset of packages in distro repositories; breaking C++ happens a lot more than C, but it happens.
This caused cargo to install different minor versions than it would have a year ago despite a lock file being present.
These minor version updates were relying on newer rust version features and then failed to build on the old version of the rust compiler I was using.
Updating rust made the build work again, but now with additional warnings (where the code I was compiling did shady things which old rust wouldn’t detect but new one did), but it did finally produce a usable binary.
Still, I was a bit miffed by cargos behavior of ignoring minor versions locks in the lock file and installing later versions than what was locked.
What good is a package lock file if it isn’t respected?
Both behaviors can be surprising. We picked one. It happens. I am not sure myself if it was the right choice or not.
This particular issue is in regard to `cargo install`: https://github.com/rust-lang/cargo/issues/7169
Oh, or, I guess, it might be how the version is specified--guess we need some more details on what "compile something after it wasn’t touched for a year" entailed.
I think that's pretty good, especially for such a young language with some ongoing significant changes. And I think that's stable enough for a production environment where there's an expectation of minimal ongoing maintenance. It means you rarely have to touch your code through updates, but occasionally will need to tweak something.
But it does add up, and something 5 years old is decently likely to not compile. I personally ran into something like that digging up an old project, and the problem is it's hard to incrementally fix it, since at that point all the dependencies are quite old, too. And there's a complex relationship between the dependencies snapshotted at that moment, and so probably you can just update them all to the very newest version and they'll be compatible, but somewhere in the middle is hard.
There are some project more focused on that but even them eventually give up on supporting all versions of their deps. Likewise for compilers, pretty much regardless of the language. I mean the only way to stay perfectly compatible with random codebase is to keep the compiler even bug compatible with older ones, which is not particularly interesting...
gcc seems to not always be backward compatible in practice. clang too. msvc too.
From their perspective, who cares what the error is? They formed an intent, and then your stupid computer software instead of fulfilling their intent did something else. This is your fault.
For example maybe I wanted to delete the old data, and I typed "rm new-data". Don't tell me that deletes the new data, I can see that now, it's your fault that the new data is deleted, I wanted to delete the old data.
For a UX point of view, where possible try to offer "Undo". The user doesn't care that shooting themselves in the face was a bad idea, and they definitely don't care that you made them click "Yes, really, in my face, I understand this will hurt" three times first, now that they've done it, and it hurts, they want to undo it. Adding a forth confirmation step will not reduce the complaints.
Sometimes it will be hard to "undo". But you should periodically revisit decisions about that over the lifetime of a piece of software as resources increase. If you have 64KB bytes of RAM it's understandable if I can't undo "fill circle" in v1 of your Freeware art program. It's much less understandable in version 16 of the $100 program on a 16GB PC...
Would it make sense to be able to "undo" a Rustup even though that's difficult? Maybe. It's worth at least considering.
And yes, it is nice that Rust has a helpful community who might try to help you fix problems if you explain what the problem is, but this isn't really about Rust, it's about Users.
Therefore the onus is on Firefox to provide a good user experience.
The question then is how does someone define backward compatibility?
The answer is a formal definition of what the expected behaviors and expectations of the programming language in question. This usually means a language specification or extensive unit tests that effectively define what the programming language should or should not do for a given set of circumstances.
As someone who's invested a lot of time in PLT and even at one point had their name on a draft of the Haskell standard, the unfortunate reality is that language specifications are very often not useful to the wide majority of people, while being quite laborious to produce and maintain and work with over time. The culture of computer programming, at large, is part of this, it's not some mathematical fact, but a social one. At the end of the day, what constitutes "Rust the language" in any formal capacity doesn't matter; "Rust the language" is a social construct in that sense, a guarantee Rust will still be Rust even if some minor bugs are fixed that they let slip by. This is how most people think of it, when you get down to the nitty gritty.
I'll also say that tons of regressions happen in mature languages with backwards compatibility. Ask any Linux distro maintainer! I don't even keep track of all the weird reasons regressions happen anymore; it's like counting sand on a beach. It's not a happy fact of life, but it is what it is, and regressions do happen, no matter if your language is stable for 5 years or 50.
What you are describing is the less fun and sometimes tedious nature of software maintenance.
It can be thankless work, but it is very important work to ensure that a programming language is reliable and to minimize the regressions that sometimes occur.
It is very much a social contract, but essential so that expectations are met, particularly for systems programming that Rust targets.
I wonder if anyone has ever tried to create a literate programming-style specification for programming languages--something that combines the high-level descriptions of programming language semantics with executable unit tests. Such a system would provide detailed semantics and give programming language creators and maintainers a good way to prevent regressions and create RFC branches to try out and test new ideas. It would help to bring the social constructs of the programming language closer to the technical implementation semantics.
The Ada programming language has a specification: http://www.ada-auth.org/standards/rm12_w_tc1/html/RM-TTL.htm...
and a conformity test suite: http://www.ada-auth.org/acats.html
which ensure that any Ada implementation conforms to what the specification requires.
Does anything similar exist for other programming languages? If so which languages have conformity tests or similar?
I use Ada professionally and Rust as a hobbyist. Rust is moving very fast and I would like to see it mature for use in safety critical domains.
Also, thank you for your work on Haskell.
It is informative for example to review talks Bjarne gave about C++ Concepts in 2015 compared to the C++ 20 feature Concepts. That's five years to get something similar in scope into the actual language standard, and of course since this isn't exactly what Bjarne designed, you then to have transition compilers and codebases to the actual standard feature...
I'm dubious about the value of conformance testing as a deliberate exercise. In practice real world implementations will definitely be defective and it's important that defects are cured when identified, mostly by changing implementations but sometimes in reality by changing the specification to reflect what is implemented. But I don't know how much value I believe there is in somebody sitting down to try to construct a test suite starting from the standards documents, rather than gathering minimal samples of real world code that did not do what the standard says it should do so that implementations can check they get those right (and where appropriate the standards body can reconsider whether the standard itself is wrong here). It appears to me that ACATS tries to do the former, right?
Some quotes from the linked page:
> Ferrocene is a sustainable effort led by Critical Section GmbH, a newly formed Ferrous Systems subsidiary, tasked with making Rust a first-class language for mission and safety-critical systems. Ferrocene produces a qualified Rust compiler toolchain. General availability is expected by the end of 2022.
And also:
> Ferrocene is a vehicle for a versioned Rust and MIR specification, paired with automated verification of Rust semantics. These "runnable specs" give developers in mission-critical and high-security environments a sound, proven, and addressable foundation for building critical libraries, analysis tools, and further system assurances.
And also:
> Critical Section will maintain designated legacy versions of the Rust toolchain and supporting utilities. This support includes backporting fixes of critical language and standard library issues (performance bugs, unsoundness, security) and maintaining key rustc targets, including test cases and platform-specific testing.
And finally:
> Ferrocene is a principled project with much work ahead, requiring cross-industry collaboration and continuous feedback. It has support from crucial industry partners and subject experts, and we're building a thoughtful community.
> Right now, Ferrous Systems and Critical Section are calling for additional partners to join this effort. We're currently looking for partners from diverse industries
I had the same experience trying to use older versions of Rust or trying to use newer versions of rustc on older crates. It doesn’t “just” work. For many of us this coming from Go, this seems like a step backwards.
I’m thankful OP had the courage to post this note about his experience. I’m also disappointed to see members of the Rust community to suggest its a failing on OP’s part that they were not able to get Firefox to build and that bringing up this difficulty is something OP was wrong to do.
I don't think its apt to call the people critiquing the critique "apologists" when the entire original blog post seems to be misunderstanding on the part of the blogger. Posts that critique things the poster do not understand tend to themselves generate critical feedback which seems fairly measured to me.
I have read the blogpost... and this isn't really the substance of the complaint? It is Mozilla's fault really to be honest, they should be sticking to a nightly if they want to use weird and non-standard features.
I personally think the only similarly between yours and the authors' is the (supposed) unmet promises of backwards compatibility - guess what, I code in different languages (including Go) and I can see breakages regularly, mostly not due to breaking a "backwards compatible" promise but because the broken code has been always there, just not being enforced by the compiler. Specifically in Rust, the backwards compatibility promise wasn't Microsoft's "everything including undocumented features" backwards compatibility: it was only limited to documented features used properly. This can surprise people who relies on the Microsoft definition of backwards compatibility.
But instead of taking a moment to read and understand the error messages, or ask the community for help with understanding them, OP chose to publish and popularise a blog post without including the error messages (or any context that would help anyone to make up their own mind based on actual facts).
Courage is not the word I would use.