8 ms·
Rust promised to not introduce breaking changes willy nilly since 1.0.0. If the change would break some previously working code, they need to go through a depre
by roblabla 4y ago
Rust promised to not introduce breaking changes willy nilly since 1.0.0. If the change would break some previously working code, they need to go through a deprecation period. This is probably the issue here.
- School-Cotton 4y agoAs always when I see this claim, I feel compelled to point out that the Rust team’s claim is simply not true, since they don’t regard adding new functions to existing impls in the standard library as a breaking change, even though it can make working code stop compiling or even do something different.
- jefftime 4y agoDo you have an example where adding a function to the std library broke existing code? I wasn't aware this was possible
- School-Cotton 4y agoIt is possible. If you implement a trait with a function “foo” on some stdlib type, then “foo” is added to the type’s inherent impl, the inherent function will now be called instead of the one in your trait when doing x.foo()
- jmillikin 4y agoThe canonical example is when a library has extended a standard trait -- adding a new trait method can cause errors due to ambiguity. Say you had the following code: mod rs_std { pub trait StdGreetings { fn hello(&self) { println!("Hello!"); } } } use rs_std::StdGreetings; trait MyGreetings: rs_std::StdGreetings { fn good_morning(&self) { println!("Good morning!"); } } struct MyGreeter; impl StdGreetings for MyGreeter {} impl MyGreetings for MyGreeter {} fn main() { let g = MyGreeter{}; g.hello(); g.good_morning(); } This is totally valid, it'll compile, and it's not an unreasonable use case to want to extend standard traits like `io::Write`. The problem is that a newer version of the standard library might have this: pub trait StdGreetings { fn hello(&self) { println!("Hello!"); } fn good_morning(&self) { println!("Good morning!"); } } And now that existing code will fail to compile. The Rust team's answer to this is "crater runs", where they build the current versions of all packages on crates.io with the new compiler to predict the ecosystem impact of a potential change.
- physPop 4y ago> The Rust team's answer to this is "crater runs", where they build the current versions of all packages on crates.io with the new compiler to predict the ecosystem impact of a potential change. Wow! I never knew this. What a fantastic use case for good, automatic, CI.
- LegionMammal978 4y agohttps://github.com/rust-lang/rust/issues/88967 https://github.com/rust-lang/rust/issues/88967: they've delayed adding an `Iterator::intersperse()` method to the standard library, since it conflicts with the `Itertools::intersperse()` method from the popular `itertools` crate.
- deleted 4y ago[deleted]
- burntsushi 4y agoAnd whenever this claim comes up, it's time to point to the API evolution RFC that outlines which kinds of breaking changes are acceptable or not: https://rust-lang.github.io/rfcs/1105-api-evolution.html https://rust-lang.github.io/rfcs/1105-api-evolution.html It's a classic communication problem. When we talk about breaking changes, we talk about what we have defined to be a breaking change. Obviously, if our definition didn't come close to approximating what a literal breaking change is in practice, then it wouldn't be a very good one. Similarly, if our definition were equivalent to a literal breaking change, then it also wouldn't be a very good one because it would prevent way too many types of additions that do not look like they should be a breaking change. It's likely it would have been better to design the language such that there was no gap in the definition of "breaking change." But that never happened and probably never will. As a mitigation mechanism to bridge the gap, we use a tool called crater that checks whether changes break compilation of published code. It is by no means perfect, but it helps. For example, if a change breaks code but would otherwise be acceptable API evolution, we will often not do it or otherwise proceed more carefully.
- est31 4y agoYeah and note that this RFC is older than 1.0, so very likely older than any of the code that was "broken" by the addition of a function. Also note that you have to go out of your way to get broken by such additions: you have to declare a trait, then implement that trait for a group of types that you didn't define, and then use that trait on standard library types. Only then will you come into conflict. Also, if you used a name that would never end up in the standard library, you are also safe. Last, often additions of functions are held back because of the breakage they would cause.
- IshKebab 4y agoYeah I feel like 0 breakage is just an unnecessarily strict goal. I like Typescript's approach. They just try to minimise breakage. Also probably worth noting that JavaScript adds new functions that could break existing code all the time and I haven't heard anyone ever complain about it.
- 4y ago
- jmillikin 4y agoYou may want to re-read roblabla's post. The Rust team has never promised that they will never break existing code, since that would lock them into a situation similar to C/C++. Making occasional rare changes that break working code (but for which it's possible to write code that works in both versions) is not "willy nilly". For example, the following compiles with the current stable version (1.63.0): use std::ffi::*; mod my_ffi { pub type c_char = u8; } use my_ffi::*; fn main() { println!("c_char is {} bytes", std::mem::size_of::<c_char>()); } But it will break when 1.64.0 is released, because then `c_char` would become ambiguous.
- pjmlp 4y agoC and C++ do have enough breaking changes. Dropping K&R C syntax, exception specifications, auto_ptr,....
- TakeBlaster16 4y agoThere is a spectrum from obvious breaking changes (removing a method), to non-obvious ones (trait methods, glob imports), and beyond (https://xkcd.com/1172/ https://xkcd.com/1172/) Before adding methods to a trait, they test the change against all public Rust code known to exist, to verify no breakage. Very occasionally this causes them to put plans on hold or work with downstream library authors (see: the num-traits crate) For the benefit of closed-source code, they also emit a warning before the change is made, so you have time to prepare or give feedback (https://doc.rust-lang.org/stable/nightly-rustc/rustc_lint/builtin/static.UNSTABLE_NAME_COLLISIONS.html https://doc.rust-lang.org/stable/nightly-rustc/rustc_lint/bu...) It's a perfectly reasonable policy. I'm not sure what more they could do, unless you expect them to literally never change any traits ever again and ossify the stdlib into whatever state it was in 2015 when Rust 1.0 was released. If that's what you want, pin your compiler/library versions and you can have it!
- School-Cotton 4y agoI’m fine with the current policy. What I would like them not to do is advertise “no breaking changes” as a major selling point of Rust, when that isn’t actually true.
- jmillikin 4y agoWhere do you see the Rust team claiming they will make no breaking changes? Note: answers like "an anonymous nobody on Twitter says Rust is better than <other language> because it never breaks compatibility" get zero points.
- School-Cotton 4y agoHere is Steve Klabnik, who is on the rust team (or at least used to be), claiming that code that doesn’t compile on a newer language revision “relies on unsound things”: https://news.ycombinator.com/item?id=32063749 https://news.ycombinator.com/item?id=32063749
- 4y ago
- howinteresting 4y agoHere's the thing. Your rules lawyering doesn't matter. What matters is whether those changes are disruptive enough that people stop using Rust.
- nicoburns 4y agoAre there any programming languages which consider adding new functions to the std library a breaking change?? I know it technically is, but it seems to me that this is ignored everywhere, not just in Rust.(because the chance of breakage is small, and you wouldn't be able to make much in the way of meaningful changes otherwise).
- School-Cotton 4y agoIn C++ it should only happen if you do “using namespace std;”, which is basically explicitly opting in to this issue.