> Can you list the these `aggressive` breaking changes?
Changing the size of int. Changing methods to introspect the type of their arguments and do things differently. And so on.
> There were only 7 releases since go1 and I fail to find any breaking change in the language specification. On the other side each Rust release has a fat list with "BREAKING CHANGES".
Because we have a very specific definition of "breaking change" that is primarily concerned with the practical effect of changes we make. Go does not consider these changes "breaking". Using Go's definition (changes to the language definition), we have no "breaking changes".
If we were to change the size of int (something we will not do, by the way, due to the practical effects of making such a change), then we would list it under "breaking changes", even if we were technically allowed to do it. That's because we care about the practical effects of our changes, not just the letter of the language definition.
> Many Rust packages only work with specific Rust versions(i.e. nightly).
Because they are explicitly opting into unstable features that are carefully marked as such. We can't stop packages from doing that. Nor can any other language.
> The rust ecosystem(std lib, tools etc) is also way behind Go in terms of stability.
The parts of the Rust standard library that are marked stable have remained completely backwards compatible, in both interface and implementation.
> Why do you need rustup if Rust is so backward compatible?
Because it's nice to keep your compiler up to date and to target different platforms?
You are right about the compiler changes but even so you can't compare 1-2 compiler BK with Rust which has language changes as well. Compiler changes are the norm in Rust.
>> The parts of the Rust standard library that are marked stable have remained completely backwards compatible, in both interface and implementation.
Rust doesn't have backwards incompatible language changes.
> This looks like a breaking change on a stable API.
No. It is a method addition. It is breaking only in the sense that code that didn't explicitly invoke the previous "as_ref" method might call this new method instead. It's the moral equivalent of:
type A struct { ... }
type B struct {
A
}
func (a ﹡A) Foo() {}
and then a later version of Go adds a method:
func (b ﹡B) Foo() {}
Such that code that called Foo() on an instance of ﹡B might call the new method instead. Go can make those changes.
Compiler changes are the norm everywhere? I'm not sure what you're trying to say here.
> This looks like a breaking change on a stable API. Am I wrong?
Yes and no.
Rust's policy on breaking changes is that changes that can be fixed by properly qualifying an implicit path are not breaking. Otherwise, adding any method to anything would be a breaking change. In this case, you can use the UFCS syntax to disambiguate.
So it's an "allowed" kind of breakage because not allowing this means freezing the stdlib.
(Go doesn't have this issue due to lack of generics, overloading, and interface-based overloading. Edit: actually, go does too, due to inheritance, but that is easier to avoid and isolate. In rust you can always write client code that breaks if the stdlib adds a method, anywhere. This is true for most typed languages).
Anything that has the chance of practically breaking things is still run through crater (which tests impact on the ecosystem) and as you can see that PR had minimal impact.
Steve has pointed out that go did have this issue as it has a limited level of auto-deref, which it has changed in the past: implementations performed two levels of auto-deref when executing methods when the spec only requires one, the implementations were changed to only allow a single auto-deref: https://golang.org/doc/go1.4#methodonpointertopointer
Right. However, as I mentioned in the edit, you can still be careful about avoiding breaking changes through inheritance and autoderef in the evolution of Go's stdlib. It forbids very specific types of methods from being added, and if you avoid that, you can continue to add methods as if nothing is wrong.
Rust (and C++, because SFINAE, and many other languages), on the other hand, technically has a breaking change each time any method is added to any public type in the stdlib. It's always possible that the client lib was using a trait method of the same name, and now has to fully qualify the method call.
https://doc.rust-lang.org/reference.html , which is accurate, but not always 100% up to date with the latest RFCs. There's also work on a formal, proven specification of the memory model, but that's not done. It'll be a while.
That's understandable. I've just tried to prove the point that Rust is still a language in flux compared with Go, hopefully making the Rust team aware why some developers hesitate to use Rust on new projects.
> I've just tried to prove the point that Rust is still a language in flux compared with Go, hopefully making the Rust team aware why some developers hesitate to use Rust on new projects.
That's not what I've seen from your comments. Instead I've seen some confused arguments about what "prose only" means (anyone in the PL field would consider both Rust and Go's documentation "prose"), combined with incorrect statements about both Rust and Go and a completely baseless assertion that Rust is "a language in flux".
Changing the size of int. Changing methods to introspect the type of their arguments and do things differently. And so on.
> There were only 7 releases since go1 and I fail to find any breaking change in the language specification. On the other side each Rust release has a fat list with "BREAKING CHANGES".
Because we have a very specific definition of "breaking change" that is primarily concerned with the practical effect of changes we make. Go does not consider these changes "breaking". Using Go's definition (changes to the language definition), we have no "breaking changes".
If we were to change the size of int (something we will not do, by the way, due to the practical effects of making such a change), then we would list it under "breaking changes", even if we were technically allowed to do it. That's because we care about the practical effects of our changes, not just the letter of the language definition.
> Many Rust packages only work with specific Rust versions(i.e. nightly).
Because they are explicitly opting into unstable features that are carefully marked as such. We can't stop packages from doing that. Nor can any other language.
> The rust ecosystem(std lib, tools etc) is also way behind Go in terms of stability.
The parts of the Rust standard library that are marked stable have remained completely backwards compatible, in both interface and implementation.
> Why do you need rustup if Rust is so backward compatible?
Because it's nice to keep your compiler up to date and to target different platforms?