Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: Policy on semver and API evolution #1105

Merged
merged 15 commits into from
Jun 10, 2015

Conversation

aturon
Copy link
Member

@aturon aturon commented May 4, 2015

This RFC proposes a comprehensive set of guidelines for which changes to
stable APIs are considered breaking from a semver perspective, and which are
not. These guidelines are intended for both the standard library and for the
crates.io ecosystem.

This does not mean that the standard library should be completely free to make
non-semver-breaking changes; there are sometimes still risks of ecosystem pain
that need to be taken into account. Rather, this RFC makes explicit an initial
set of changes that absolutely cannot be made without a semver bump.

Along the way, it also discusses some interactions with potential language
features that can help mitigate pain for non-breaking changes.

The RFC covers only API issues; other issues related to language features,
lints, type inference, command line arguments, Cargo, and so on are considered
out of scope.

Rendered

@aturon
Copy link
Member Author

aturon commented May 4, 2015

@bstrie, I know you were interested in this.
@pnkfelix I could use your careful eyes on this one!
cc @alexcrichton @sfackler @brson @huonw @wycats @nikomatsakis

@aturon
Copy link
Member Author

aturon commented May 4, 2015

cc @reem @carllerche -- I think both of you have also expressed some opinions on this topic as well. (This is an important piece of policy, so I want to ensure good visibility).

to disambiguate are not automatically "major" changes. (But in such cases, one
must evaluate how widespread these "minor" changes are).

* In principle, it should be possible to produce a version of the code for any
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A slightly weaker way of phrasing this would be "given knowledge of any change, it should be possible to write a version of your code that works both before and after that change". It seems to me like that phrasing is significantly more important to guarantee than the version written, since it means libraries won't be "forced" to abandon old versions of Rust to support new versions.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's also an important constraint, and I'll try to rewrite to clarify.

That said, what's gradually becoming clear to me with this RFC is that we may be able to make a strictly stronger guarantee: that all minor but breaking changes can be worked around automatically with an elaboration process. (I think with a couple of very minor language features, we can get there.) Having a strong guarantee that you don't have to go make changes to your dependencies when you upgrade Rust -- while allowing the standard library to grow -- seems like a great place to be.

@nikomatsakis
Copy link
Contributor

@aturon I'll go over in detail, but one thought I had is that it might be useful to elaborate a kind of "best practices for forwards compatibility". That's probably not part of this RFC, but it might help illuminate nonetheless.

Along the way, it also discusses some interactions with potential language
features that can help mitigate pain for non-breaking changes.

The RFC covers only API issues; other issues related to language features,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: redundant paragraph. Language, lints, type inference, CLI are not part of standard library (first paragraph), nor they are a part of crates.io ecosystem.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the past, for better or worse, sometimes changes to things like command line arguments to rustc were for various reasons classified as "library issues" (as opposed to language issues).

(Also, the list here covers things that might be part of semantic versioning for the Rust language itself -- I think the rules there still remain unwritten. So given that the title of this RFC is "policy on semver ...", it is natural for a reader to perhaps wonder if these issues are in fact addressed...)

While the first paragraph does indeed restrict the domain to "standard library" and "crates.io ecosystem", I think this paragraph can stay -- perhaps just modify it to make it clear that this paragraph is in fact a consequence a fact that all these things are not part of the standard library nor crates.io ecosystem.

@BurntSushi
Copy link
Member

I very much love this RFC. Nice work @aturon!

Adding any item without a default will immediately break all trait implementations.

It's possible that in the future we will allow some kind of
"[sealing](#sealed-traits)" to say that a trait can only be used as a bound, not
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This link is dead.

@theemathas
Copy link

What happens if someone finds another way to cause unsafty using safe code and the standard library? We already had thread::scoped and Vec::drain.


As with "[Signatures in type definitions](#signatures-in-type-definitions)",
traits are permitted to add new type parameters as long as defaults are provided
(which is backwards compatible).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not true, consider the change to Iterator::sum, which (even though it specifies a default for the type parameter) can't be inferred everywhere.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspect that is the same problem discussed below: https://github.com/rust-lang/rfcs/pull/1105/files#r29635875

@apasel422
Copy link
Contributor

Should this mention changing an object-safe trait in such a way that it is no longer object-safe?

@theemathas
Copy link

What about changing an unsafe function to a safe function?

@ruuda
Copy link

ruuda commented May 7, 2015

There are two angles to versioning, and I think the difference is important:

  1. Given that the next release will not be major, can we include this change?
  2. Given that we are going to include this change, what should the version number for the next release be?

If I understand the release train model correctly, the version number is determined before changes that will be included in that version are made, so Rust is in scenario 1. If major bumps are going to be uncommon, then it makes sense to downplay some technically breaking changes as minor.

For Crates.io, I expect the vast majority of crates to be in scenario 2. I think the pragmatic approach is a good one; adding a public item without changing anything else certainly feels like a new feature, not like a backwards incompatible change. However, to play the devil’s advocate: there appears to be a hidden assumption that a major version bump is bad and should be avoided. I agree that backwards incompatible changes should be avoided if possible, but this RFC is about naming only. If a change is technically breaking and will be included in the next release, the only question is what the version number should be. Why downplay technically breaking changes as minor? To quote the sidebar rules:

5 . Chill out! A programming language version number is a silly thing to get upset over.

@alexcrichton
Copy link
Member

This RFC is now entering the week-long final-comment period.

@huonw
Copy link
Member

huonw commented Jun 3, 2015

I'm in favour, but I think that we will definitely want to be "quick" to make amendments (to the process, even if we don't literally change the text here) in future as we gain more experience, and as the ecosystem/community changes.

(I'm also a little nervous about #1105 (comment) .)

@comex comex mentioned this pull request Jun 5, 2015
@alexcrichton
Copy link
Member

The consensus of the library subteam is to merge this RFC. We may tweak the specifics here and there over time, but there is broad consensus among the core ideas behind this RFC and minor updates are always fine to make later!

@aturon
Copy link
Member Author

aturon commented Sep 25, 2015

It occurred to me today that this RFC did not take into account the impact of "OIBIT" traits (which have a .. impl). In particular, these traits can introduce downstream sensitivity to every aspect of a data type's representation, even if that representation is private.

Effectively, OIBITs make it possible for downstream crates to make promises on behalf of upstream crates that can easily be broken.

I don't think this should change anything about the policy itself, but it'd be worth amending the RFC to discuss it.

RFC issue

@mzabaluev mzabaluev mentioned this pull request Nov 18, 2017
sgrif added a commit to sgrif/rfcs that referenced this pull request May 30, 2018
RFC rust-lang#1023 introduced rules that exclude impls which should clearly be
valid. It also used some ambiguous language around what is a breaking
change, that ended up being completely ignored and contradicted by rust-lang#1105.
This RFC seeks to clarify what is or isn't a breaking change when it
comes to implementing an existing trait, and conservatively expands the
orphan rules to allow impls which do not violate coherence, and fit
within the original goals of rust-lang#1023.

[Rendered]
sgrif added a commit to sgrif/rfcs that referenced this pull request May 30, 2018
RFC rust-lang#1023 introduced rules that exclude impls which should clearly be
valid. It also used some ambiguous language around what is a breaking
change, that ended up being completely ignored and contradicted by rust-lang#1105.
This RFC seeks to clarify what is or isn't a breaking change when it
comes to implementing an existing trait, and conservatively expands the
orphan rules to allow impls which do not violate coherence, and fit
within the original goals of rust-lang#1023.
@sgrif sgrif mentioned this pull request May 30, 2018
@Centril Centril added A-versioning Versioning related proposals & ideas A-stability Proposals relating to policy and changes about stability of features. labels Nov 23, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-stability Proposals relating to policy and changes about stability of features. A-versioning Versioning related proposals & ideas final-comment-period Will be merged/postponed/closed in ~10 calendar days unless new substational objections are raised. T-libs-api Relevant to the library API team, which will review and decide on the RFC.
Projects
None yet
Development

Successfully merging this pull request may close these issues.