4 ms·
When they ask if an update to a stable compiler has broken their code, what does this mean exactly? I had thought that a goal of Rust was to always maintain bac
by squiguy7 9y ago
When they ask if an update to a stable compiler has broken their code, what does this mean exactly? I had thought that a goal of Rust was to always maintain backwards compatibility?
I know how hard this is to pull off and I am not trying to say they have done a poor job; I genuinely want to know what others consider a breaking change.
- steveklabnik 9y agoIn a language that's as strongly typed as Rust, any change can be breaking. So for example, let's say that you had code that looks like this: use std::cell::*; struct MoveCell; We then add a new type to std::cell, also named MoveCell. Your code will now fail to compile, as the two structures conflict. This kind of breakage can still happen, even though we care a lot about stability.
- gcp 9y agousing namespace always backfires.
- squiguy7 9y agoAh that makes sense. I suppose you can't predict naming in everyone's source for their projects. Thanks for the answer!
- steveklabnik 9y agoNo worries. There is also other things as well, that's just one of the easiest ones to explain. For example, in 1.20 last week, we fixed a bug with include! in documentation tests behaving strangely; that's technically a change in behavior, and therefore, a breaking change. Two crates were the only users, apparently, and so they just wrote a patch and fixed it. Still technically breakage. The guiding principle is "it should not be painful to update the compiler", and I think we do as good a job as we can making sure that that's true.
- nickm12 9y agoIt would be helpful in these guidelines to make a clear distinction between changes that result in "code not compiling" versus "code behaving differently". It seems like the vast majority of cases you've enumerated are in the category of "code won't compile". Perhaps some have a knee-jerk reaction against this, but to me this is kind of incompatibility seems much more preferable to the other, especially if the update required to the code is trivial and obvious.
- Manishearth 9y agoTo expand on this, we consider the following changes to be okay or "not really a breaking change" (see also: https://blog.rust-lang.org/2014/10/30/Stability.html#what-are-the-stability-caveats https://blog.rust-lang.org/2014/10/30/Stability.html#what-ar...): - Patching up soundness holes causing previously-unsound code to error (https://github.com/rust-lang/rust/pull/43651 https://github.com/rust-lang/rust/pull/43651 is an example) - Changing inference in a way that may require new annotations - Adding types and things to modules which may cause clashes on glob imports (steve's example above) - Adding methods to types (this may cause code calling trait methods to require disambiguation via the fully qualified UFCS syntax) - Adding new trait impls (similar disambiguation issues) - Lint changes (If you `#[deny(lint)]` a lint, this may cause compilation failures). Cargo passes --cap-lints=warn to dependencies so a lint change will at most cause your dependencies to spew extra warnings and cause your code to stop compiling, in a way that's trivial to fix (allow the lint, or fix the warning). In general for all releases we run cargobomb to look out for breakages, both "okay" ones and not okay ones. Additionally, for the first two kinds of breakages (and other miscellaneous iffy changes) we proactively cargobomb. Even if something is technically allowed by our stability rules we want to make sure that practically speaking it has minimal impact.
- frankmcsherry 9y agoOne of the PITA aspects of this type of break is when library writers need to change (via hard break) their external APIs because Rust has made a "minor break that can be easily fixed". For example, one of the timely traits had `min` and `max` methods, as it corresponded to a type with upper and lower bounds. Rust added `min` and `max` convenience methods to all implementors of `Ord` (which this type was), which now means that anyone who wants to use the type needs to use UFCS. Or, I issue a major break so that their lives don't suck (now `minimum` and `maximum`). The Rust change was classified as fixing a "papercut", so that folks wouldn't have to `use std::cmp::{min, max};`, but it's a pain in the arse when it's done so casually.
- aturon 9y agoYeah, it's really hard to strike the right balance here, and we're constantly learning from experience. Sorry for the pain! I'll put a note on the core team agenda to undergo a round of public discussion around policies here, which is overdue at this point.
- frankmcsherry 9y agoMaybe a different way to frame it is: Rust provides a stability guarantee for `rustc`, but you could just as easily prioritize stability for the Rust ecosystem. If Rust gets some neat new features that break crates, the experience of stability for users is still missing. Feel free to factor in that approximately five people use crates that I write, and most of them have bigger problems than Rust breakage. :)
- smitherfield 9y ago> In a language that's as strongly typed as Rust Isn't this more-or-less true of any statically-typed language? I can't think of any off the top of my head that have the behavior of implicitly re-defining a type when a new definition is encountered after another definition was previously brought into scope. Even C isn't that sadistic: $ echo "\ > #include <time.h> > struct tm {};" | cc -ansi -xc - <stdin>:2:8: error: redefinition of 'struct tm' struct tm {}; ^~ In file included from <stdin>:1:0: /usr/include/time.h:74:8: note: originally defined here struct tm { ^~
- steveklabnik 9y agoAbsolutely, I was trying to communicate that this is true across a ton of languages. This one isn't super specific to Rust; others may be depending on the exact feature.
- heinrich5991 9y agouse std::cell::*; struct Cell; works: Local names shadow glob imports.
- erickt 9y agoRust Core/Community Team member here, who helped design the survey. You got it. We asked this question to check whether or not we're succeeding at maintaining our backwards compatibility. While we have great visibility on if we're breaking our open source community with tools like cargobomb [1], we don't have great visibility into running tests against our commercial users (which we got a ton now! [2]). [1]: https://github.com/rust-lang-nursery/cargobomb https://github.com/rust-lang-nursery/cargobomb [2]: https://www.rust-lang.org/en-US/friends.html https://www.rust-lang.org/en-US/friends.html
- khuey 9y agoTo give another example, a change was made in the type inference engine for rustc 1.18 that resulted it in no longer inferring types in circumstances where rustc 1.17 did infer types. https://github.com/rust-lang/rust/issues/42545 https://github.com/rust-lang/rust/issues/42545
- Ruud-v-A 9y agoOne example of a breaking change that had an “acceptable count” of GitHub issues cross-referencing it is this one: https://github.com/rust-lang/rust/pull/42496 https://github.com/rust-lang/rust/pull/42496.