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: Semantic versioning for the language #1122

Merged
merged 6 commits into from
Jun 10, 2015

Conversation

nikomatsakis
Copy link
Contributor

@nikomatsakis nikomatsakis commented May 15, 2015

Define what kinds of breaking changes are permitted in a minor release (bugs, semantic fixes, clarifications) and introduce an opt-in mechanism to permit other kinds of minor additions.

Rendered view.

version. For example, if version `X.Y` adds new keywords, the
tokenizer will likely need to be configured appropriately with the
proper set of keywords. For this reason, it may make sense to require
that the `#![rust_version]` attribute appear *first* on the crate.
Copy link
Member

Choose a reason for hiding this comment

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

We could avoid some of this feedback weirdness by specifying the language version on the command line like rustc --version 1.3, analagous to e.g. gcc --std=c11. The language version could be tracked in Cargo.toml then, which would also be nice since it could be displayed with the rest of the crate's info.

Copy link
Contributor

Choose a reason for hiding this comment

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

I prefer that as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@sfackler @seanmonstar ah, interesting thought. @alexcrichton @brson @wycats -- thoughts? seems to touch on general cargo/rustc interaction.

Copy link
Member

Choose a reason for hiding this comment

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

Most options like this tend to actually show up in two places, either on the command line or in the source itself. The reason for this is rooted in our desire to be able to run the compiler independently of Cargo in an ergonomic fashion. For example a Cargo project does not specify #![crate_type] in each file, but a non-Cargo project would to avoid passing the flags to the compiler.

Along those lines I may expect that we accept both forms here. The #![rust_version] attribute would probably not be used much in Cargo, but anyone driving the compiler manually would likely leverage it to avoid passing flags everywhere. Additionally Cargo would probably grow a "Rust version" field and it would pass this argument to the crate automatically, but it would be Cargo configuration instead of configuration in the source.

All in all, I'd be fine putting this responsibility on Cargo itself, but I will personally desire the ability to put it in both places. The only snag I can think of for Cargo is that Cargo will need to detect pre---version compilers and not pass the --version flag possibly.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@alexcrichton

I am sort of inclined to limit this version to the command line because it is SO much more convenient to know what version you are "parsing as" before you begin parsing. (We could always add a #![rust_version] attribute later.)

One question is what the defaults ought to be: Presumably cargo will supply 1.0.0 by default, but I would sort of prefer if rustc used the most recent version by default. This is driven by the fact that I only run rustc by hand for small scripts etc and I imagine they will want the most recent version.

@nrc nrc added the T-lang Relevant to the language team, which will review and decide on the RFC. label May 15, 2015
breaking changes "opt-in" (and hence not really breaking), this is
still a tool to be used with great caution. Therefore, **the RFC also
proposes guidelines on when it is appropriate to include an "opt-in"
breaking change and when it is not**.
Copy link
Contributor

Choose a reason for hiding this comment

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

In the nodejs world, npm allows properties like these in the package.json. Some are engine.node, engine.npm, and engine.os. Unfortunately, some use them to try to force their preference that everyone upgrade immediately, such as stating engine.node = 0.12, even though those using nodejs in production would recommend waiting for several more point releases.

So, eventually npm stopped treating this as an error, and simply a warning.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@seanmonstar

So, eventually npm stopped treating this as an error, and simply a warning.

Interesting, thanks! I think I wrote that the equivalent scenario (specifying a version of Rust newer than the current compiler) would be a warning here as well...

@DanielKeep
Copy link

Happy to see this again! :)

I'm a little leery of version numbers being used to opt into old behaviour, but I can't think of any reasonable alternatives.

One minor suggestion: I'd like to propose that the #[rust_version] attribute be brought back, but only as a guard mechanism. That is, the presence or non-presence of the attribute cannot change the way code is parsed or compiled, it merely asserts that code is being compiled with an "appropriate" compiler version. Given the version number's use in reverting to old behaviours, "appropriate" here probably equates to "exactly as specified".

The reason I'd like to see this is for code examples. One of the justifications for my PR #457 (Rust language version attribute) was to document the language version of code snippets in documentation, articles and on sites like Stack Overflow.

In very large code bases, it might also help keep track of which parts of the code have been migrated to new versions of the compiler (especially if we're talking about changes to semantics, not syntax or types). (Of course, in that case, some sort of --ignore-version-attrs switch would probably be necessary...)

@comex
Copy link

comex commented May 28, 2015

Just a quick note in response to the meeting minutes about a hypothetical 2.0 release schedule... since the text of this RFC itself is somewhat ambiguous about how the proposed rust-version attribute would apply to new major releases. (At least I interpret that way.)

Today I can run clang and compile unchanged a C program written over 25 years ago. (Not C++, though - older C++ compilers were too permissive and so old programs break now. This is a PITA. Still, the standard itself is largely backwards compatible.) Perl 5 was first released in 1994, and I think modern Perl 5 has kept backwards compatibility from there(?). JavaScript appeared in 1995 and it - at least with standards-track APIs - has never broken backwards compatibility except in very minor ways. Python 2 is 15 years old, and has now spent almost half of its life deprecated, while new development using it continues. Look how their attempt to break backwards compatibility is going... migrating the wall of shame is/was one thing, but the long tail is another. I'd say the long tail of old, unmaintained codebases in the wild tends to last an order of magnitude longer than the popular, public, churned stuff. And I don't think that's such a bad thing.

I think Rust should live up to that standard: I want to be able to run rustc in 2040 and compile a program written for Rust 1.0. It's okay if I have to specify --rust-version=1.0, but I should be able to link to it from crates written for newer language versions. Alternately, it's okay if I have to run a migrator tool, but only if it's 100% guaranteed to make the code work (even if in an ugly way) rather than bailing out in tricky cases.

That is, all breaking changes should be opt-in changes.

Of course, I am not the one who would have to do the work for this, but I think it should be done. shrug

@glaebhoerl
Copy link
Contributor

Today I can run clang and compile unchanged a C program written over 25 years ago.

Though it might eat your laundry due to the compiler more aggressively exploiting latent UB in the code than the compilers of 25 years earlier. ;)

@nikomatsakis
Copy link
Contributor Author

I've been thinking about this RFC a fair amount. It seems to me that most everybody agrees we should fix soundness problems. What is a bit less obvious is what long-term strategy we want to use for evolving and tweaking the language.

This RFC is generally oriented around allowing us to expand the language without issuing new major versions. An alternative philosophy might be that we should be making major version releases on a regular basis, and thus backwards-incompatible changes and extensions can hitch a ride on one of these major versions instead.

There are good arguments to be made for both sides. I think the best strategy and timing for major version updates is not yet entirely clear. On the one hand, some people argue (for good reasons) that we should never issue a major release. Others that we can use major versions more regularly, at least now while Rust is young. (I think one thing that is relatively clear is that whenever we DO issue a major version, we should ensure that there is an incremental path to adopting it.)

In any case, for the time being, I think I will just remove the language on "opt-in" changes from this RFC and focus on what kinds of breaking changes are permitted.

One interesting question is whether we will accept other sorts of breaking changes that are not strictly tied to soundness, but just cases where we seem to have gotten something slightly wrong. I have exactly one example in mind at the moment (some details of trait object lifetime defaults), but I can easily imagine that this scenario will arise. Probably best is to just address such things on a case-by-case basis: every good rule needs an exception, after all.

@nikomatsakis
Copy link
Contributor Author

Just for the record, some of the hazards with the strategy that the RFC currently espouses (version numbers):

  1. The more we evolve the language, the more that online content such as tutorials and so forth bitrots. If we issue major versions, it is easier to think about (ah, that tutorial is for 1.x, not 2.x).
  2. I am worried about a proliferation of "random" version numbers -- you can't tell if the version a package declares is because it really needs it, or just happens to be the version, or what. Major versions do help here, since they accumulate things.

@nikomatsakis
Copy link
Contributor Author

Hear ye, hear ye. This RFC is entering the final comment period.

@nikomatsakis nikomatsakis added the final-comment-period Will be merged/postponed/closed in ~10 calendar days unless new substational objections are raised. label Jun 3, 2015
@comex comex mentioned this pull request Jun 5, 2015
@llogiq
Copy link
Contributor

llogiq commented Jun 5, 2015

Regarding "opting out", I would humbly request the RFC states that we should make the targeted rust version a crate attribute and also strive to ensure interoperability between crates targeting different rust versions (as much as possible).

To enact this will restrict us a bit (as we should refrain from making changes that break compatibility between crates of different rust versions unless we have very good reasons) but give users a clean update path that minimizes breakage.

@nikomatsakis
Copy link
Contributor Author

@llogiq I will add your comment to the unresolved question section. I also think I should add back some form of the text I cut, in particular mentioning that we should probably standardize some form opt out in advance, so it's ready when we need it. I don't think I like the idea of using a crate-wide attribute though -- typically I want the opt-out to be much more targeted (e.g., opt out this particular impl from the coherence rule, but not others).

@nikomatsakis
Copy link
Contributor Author

I made a few minor amendments: first, I incorporated the suggestion by @llogiq that crates which employ opt out should be compatible with those that don't, and I also added two unresolved questions (What should "opt-out" look like? Can we ever make breaking changes that are not soundness related?). These changes seem uncontroversial (though the answer to the final question may be, but that can be discussed in other venues, such as #1156.

@nikomatsakis
Copy link
Contributor Author

It's official... the language subteam has decided to accept this RFC.

@nikomatsakis nikomatsakis merged commit 2dba276 into rust-lang:master Jun 10, 2015
nikomatsakis added a commit to nikomatsakis/rfcs that referenced this pull request Jun 16, 2015
and remove the legacy attribute (also adjust text of RFC rust-lang#1122 slightly).
nikomatsakis added a commit to nikomatsakis/rfcs that referenced this pull request Jun 16, 2015
@leoyvens leoyvens mentioned this pull request Jun 3, 2016
@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-lang Relevant to the language team, which will review and decide on the RFC.
Projects
None yet
Development

Successfully merging this pull request may close these issues.