RFC: Semantic versioning for the language #1122

Merged
merged 6 commits into from Jun 10, 2015

Conversation

Projects
None yet
@nikomatsakis
Contributor

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.

text/0000-contingency-plan.md
+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.

This comment has been minimized.

@sfackler

sfackler May 15, 2015

Member

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.

@sfackler

sfackler May 15, 2015

Member

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.

This comment has been minimized.

@seanmonstar

seanmonstar May 15, 2015

Contributor

I prefer that as well.

@seanmonstar

seanmonstar May 15, 2015

Contributor

I prefer that as well.

This comment has been minimized.

@nikomatsakis

nikomatsakis May 19, 2015

Contributor

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

@nikomatsakis

nikomatsakis May 19, 2015

Contributor

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

This comment has been minimized.

@alexcrichton

alexcrichton May 19, 2015

Member

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.

@alexcrichton

alexcrichton May 19, 2015

Member

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.

This comment has been minimized.

@nikomatsakis

nikomatsakis May 21, 2015

Contributor

@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.

@nikomatsakis

nikomatsakis May 21, 2015

Contributor

@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.

text/0000-contingency-plan.md
+In cases where the impact seems larger, the following steps can be
+taken to ease the transition:
+
+1. Identify important crates (such as those with many dependencies)

This comment has been minimized.

@ruuda

ruuda May 15, 2015

Do you mean those with many dependants (i.e. crates that are a dependency of many others)?

@ruuda

ruuda May 15, 2015

Do you mean those with many dependants (i.e. crates that are a dependency of many others)?

This comment has been minimized.

@liaoarden

liaoarden May 18, 2015

👍 on crates that have many dependencies rather than crates w/ that dependent feature.

@liaoarden

liaoarden May 18, 2015

👍 on crates that have many dependencies rather than crates w/ that dependent feature.

This comment has been minimized.

@nikomatsakis

nikomatsakis May 20, 2015

Contributor

I meant crates are frequently depended on, yes, thanks.

@nikomatsakis

nikomatsakis May 20, 2015

Contributor

I meant crates are frequently depended on, yes, thanks.

text/0000-contingency-plan.md
+older behavior can be supported in the compiler, but this is expected
+to be straightforward: if supporting older behavior is hard to do, it
+may indicate that the opt-in change is too complex and should not be
+accepted.

This comment has been minimized.

@nagisa

nagisa May 15, 2015

Contributor

Sounds like a highway to code bloat. How long do we want to keep supporting a certain rust_version? Indefinitely?

@nagisa

nagisa May 15, 2015

Contributor

Sounds like a highway to code bloat. How long do we want to keep supporting a certain rust_version? Indefinitely?

This comment has been minimized.

@tshepang

tshepang May 15, 2015

Contributor

My guess is the bloat would be removed in 2.0.

@tshepang

tshepang May 15, 2015

Contributor

My guess is the bloat would be removed in 2.0.

This comment has been minimized.

@nrc

nrc May 15, 2015

Member

Presumably how long is up to the next major version.

@nrc

nrc May 15, 2015

Member

Presumably how long is up to the next major version.

This comment has been minimized.

@nrc

nrc May 15, 2015

Member

Using feature names rather than version numbers seems better to me. For any given Rust version there will be some (hopefully documented) list of features which are supported in some way, but also some (non-opt-in) features which are not. Furthermore, a crate might want to use feature A which was removed in version 1.4 (say) but also want to use unrelated feature B which was introduced in 1.5. Will the compiler support this? It is at best confusing for the user. Also confusing is that presumably a library compiled on version 1.8 of the compiler but using #![rust_version="1.7"] will be ABI compatible with a binary generated using the same compiler but no version attribute, but not with a binary from the actual 1.7 compiler.

@nrc

nrc May 15, 2015

Member

Using feature names rather than version numbers seems better to me. For any given Rust version there will be some (hopefully documented) list of features which are supported in some way, but also some (non-opt-in) features which are not. Furthermore, a crate might want to use feature A which was removed in version 1.4 (say) but also want to use unrelated feature B which was introduced in 1.5. Will the compiler support this? It is at best confusing for the user. Also confusing is that presumably a library compiled on version 1.8 of the compiler but using #![rust_version="1.7"] will be ABI compatible with a binary generated using the same compiler but no version attribute, but not with a binary from the actual 1.7 compiler.

This comment has been minimized.

@nikomatsakis

nikomatsakis May 20, 2015

Contributor

@nrc

I prefer version numbers primarily, I think, because it's a clearer model for end-users: you are using Rust version X.Y, not Rust with feature X and feature Z. That is, I like to think of Rust as a cohesive whole, not a kind of fragmented landscape.

What prior art I could find in this area seems to focus on version numbers. I am thinking of Java and C (--lang=ansi, etc) primarily, and secondarily of XSLT (a language that I happen to have used a lot, but I imagine relatively few others). I don't know how C# handles things and would be curious to know.

Python has the import from future mechanism which is keyword based, but it works rather differently. It is not intended as a long-term mechanism for allowing older code to continue working, but rather a way to signal that you'd prefer to opt-in to a change that will later become universal.

That said, other languages release less frequently, so maybe version numbers work better there (i.e., the new features from Java 1.8 vs Java 1.7 are going to be easier to remember than Rust 1.22 vs 1.23).

Furthermore, a crate might want to use feature A which was removed in version 1.4 (say) but also want to use unrelated feature B which was introduced in 1.5.

I don't anticipate removing features at all, so I don't imagine this scenario would arise. At most, I would think we would just deprecate a feature, but it would remain unavailable. In any case, this kind of "pick and choose" scenario also just feels like the kind of thing I want to avoid as much as possible. Knowing that you're ensuring compatibility to an older Rust seems ok. Knowing that you're ensuring compatibility to a random "variant" on Rust consisting of some features but not others seems less good.

Also confusing is that presumably a library compiled on version 1.8 of the compiler but using #![rust_version="1.7"] will be ABI compatible with a binary generated using the same compiler but no version attribute, but not with a binary from the actual 1.7 compiler.

That's an interesting point, but seems like a non-sequitor to me. In other words, you're correct that someone could be confused, but it seems like, ultimately, we should just fix the ABI problems so that, in fact, the binaries that get produced ARE compatible (and perhaps have some mechanism for emitting binaries in older formats, if necessary). Given that we are talking about "additive" features here that should always be possible, I would expect, though it will take effort to design things properly.

@nikomatsakis

nikomatsakis May 20, 2015

Contributor

@nrc

I prefer version numbers primarily, I think, because it's a clearer model for end-users: you are using Rust version X.Y, not Rust with feature X and feature Z. That is, I like to think of Rust as a cohesive whole, not a kind of fragmented landscape.

What prior art I could find in this area seems to focus on version numbers. I am thinking of Java and C (--lang=ansi, etc) primarily, and secondarily of XSLT (a language that I happen to have used a lot, but I imagine relatively few others). I don't know how C# handles things and would be curious to know.

Python has the import from future mechanism which is keyword based, but it works rather differently. It is not intended as a long-term mechanism for allowing older code to continue working, but rather a way to signal that you'd prefer to opt-in to a change that will later become universal.

That said, other languages release less frequently, so maybe version numbers work better there (i.e., the new features from Java 1.8 vs Java 1.7 are going to be easier to remember than Rust 1.22 vs 1.23).

Furthermore, a crate might want to use feature A which was removed in version 1.4 (say) but also want to use unrelated feature B which was introduced in 1.5.

I don't anticipate removing features at all, so I don't imagine this scenario would arise. At most, I would think we would just deprecate a feature, but it would remain unavailable. In any case, this kind of "pick and choose" scenario also just feels like the kind of thing I want to avoid as much as possible. Knowing that you're ensuring compatibility to an older Rust seems ok. Knowing that you're ensuring compatibility to a random "variant" on Rust consisting of some features but not others seems less good.

Also confusing is that presumably a library compiled on version 1.8 of the compiler but using #![rust_version="1.7"] will be ABI compatible with a binary generated using the same compiler but no version attribute, but not with a binary from the actual 1.7 compiler.

That's an interesting point, but seems like a non-sequitor to me. In other words, you're correct that someone could be confused, but it seems like, ultimately, we should just fix the ABI problems so that, in fact, the binaries that get produced ARE compatible (and perhaps have some mechanism for emitting binaries in older formats, if necessary). Given that we are talking about "additive" features here that should always be possible, I would expect, though it will take effort to design things properly.

text/0000-contingency-plan.md
+precisely constitutes a "minor" vs "major" change to the Rust language
+itself (as opposed to libraries, which are covered by [RFC 1105]).
+**This RFC proposes limiting breaking changes to changes with
+soundness implications**: this includes both bug fixes in the compiler

This comment has been minimized.

@nrc

nrc May 15, 2015

Member

Presumably this means until we get to 2.0, you don't mean to preclude the possibility of ever having 2.0?

@nrc

nrc May 15, 2015

Member

Presumably this means until we get to 2.0, you don't mean to preclude the possibility of ever having 2.0?

This comment has been minimized.

@liaoarden

liaoarden May 18, 2015

Also, would this essentially mean that Rust 1.0 would put semantic versioning, as specified by semvar.org, on hold until 2.0?

@liaoarden

liaoarden May 18, 2015

Also, would this essentially mean that Rust 1.0 would put semantic versioning, as specified by semvar.org, on hold until 2.0?

This comment has been minimized.

@sfackler

sfackler May 19, 2015

Member

I don't see why we wouldn't fix soundness issues in 2.0 and beyond.

@sfackler

sfackler May 19, 2015

Member

I don't see why we wouldn't fix soundness issues in 2.0 and beyond.

This comment has been minimized.

@nikomatsakis

nikomatsakis May 20, 2015

Contributor

@nrc Right, I mean that until 2.0, we limit breaking changes to bugs/soundness issues. I can clarify the language here.

@ardentsonata I think this same policy would apply to version 2.0 and beyond, though of course we could change it. That is, we will continue to fix bugs and soundness issues. I am basically trying to define more precisely what can go into a "minor change" in Rust (whether it be from 1.1 to 1.2, or 2.1 to 2.2).

@nikomatsakis

nikomatsakis May 20, 2015

Contributor

@nrc Right, I mean that until 2.0, we limit breaking changes to bugs/soundness issues. I can clarify the language here.

@ardentsonata I think this same policy would apply to version 2.0 and beyond, though of course we could change it. That is, we will continue to fix bugs and soundness issues. I am basically trying to define more precisely what can go into a "minor change" in Rust (whether it be from 1.1 to 1.2, or 2.1 to 2.2).

text/0000-contingency-plan.md
+The detailed design is broken into two major section: how to address
+soundness changes, and how to address other, opt-in style changes. We
+do not discuss non-breaking changes here, since obviously those are
+safe.

This comment has been minimized.

@nrc

nrc May 15, 2015

Member

It might be worth commenting on changes which we think are non-breaking and then when released into the wild actually are not. I expect that will be rare, and extremely so while many of our users are on nightly and beta releases. But in the future where (hopefully) most users are on the release channel, it seems possible (though hopefully still rare). Presumably for us to miss the breaking change, it must be small and subtle.

@nrc

nrc May 15, 2015

Member

It might be worth commenting on changes which we think are non-breaking and then when released into the wild actually are not. I expect that will be rare, and extremely so while many of our users are on nightly and beta releases. But in the future where (hopefully) most users are on the release channel, it seems possible (though hopefully still rare). Presumably for us to miss the breaking change, it must be small and subtle.

This comment has been minimized.

@nikomatsakis

nikomatsakis May 20, 2015

Contributor

Yes, this is a good question -- what policy do we have in such cases? Do we rollback? Stick with it? Note that this has come up already in the runup to 1.0, and we opted to stick with the change (on the grounds that some people had adapted, so changing back was even worse than status quo), but the scenario was of course different.

@nikomatsakis

nikomatsakis May 20, 2015

Contributor

Yes, this is a good question -- what policy do we have in such cases? Do we rollback? Stick with it? Note that this has come up already in the runup to 1.0, and we opted to stick with the change (on the grounds that some people had adapted, so changing back was even worse than status quo), but the scenario was of course different.

text/0000-contingency-plan.md
+`[breaking-change]` along with a description of how to resolve the
+problem, which helps those people who are affected to migrate their
+code. A description of the problem should also appear in the relevant
+subteam report.

This comment has been minimized.

@nrc

nrc May 15, 2015

Member

Is this going to cause any bump in the semver version?

@nrc

nrc May 15, 2015

Member

Is this going to cause any bump in the semver version?

This comment has been minimized.

@nikomatsakis

nikomatsakis May 20, 2015

Contributor

@nrc Apart from a minor version bump, no. That's the point of the RFC, defining what can be done in a "minor version bump".

@nikomatsakis

nikomatsakis May 20, 2015

Contributor

@nrc Apart from a minor version bump, no. That's the point of the RFC, defining what can be done in a "minor version bump".

This comment has been minimized.

@nrc

nrc May 20, 2015

Member

Sorry I wasn't clear, I didn't mean a major version bump, but that leaves three options - a minor version bump, a minor minor version (whatever they are really called) bump, or no bump at all.

I assume from your reply that this would cause a minor version bump every time?

Actually perhaps I am confused - are we using the minor version bumps for the 6-weekly release? In which case are you saying the processes in this RFC will only happen as part of that normal cycle? And/or that an out-of-cycle release will also cause a minor version bump?

@nrc

nrc May 20, 2015

Member

Sorry I wasn't clear, I didn't mean a major version bump, but that leaves three options - a minor version bump, a minor minor version (whatever they are really called) bump, or no bump at all.

I assume from your reply that this would cause a minor version bump every time?

Actually perhaps I am confused - are we using the minor version bumps for the 6-weekly release? In which case are you saying the processes in this RFC will only happen as part of that normal cycle? And/or that an out-of-cycle release will also cause a minor version bump?

text/0000-contingency-plan.md
+safe.
+
+### Soundness changes
+

This comment has been minimized.

@nrc

nrc May 15, 2015

Member

I feel like we should make some attempt at defining a soundness bug. Since we have no formal model, we are not using the formal definition here. Are soundness bugs limited to formal type soundness? Only bugs which affect Rust's major invariants. What about technically sound but unexpected behaviour from some language feature? A linguistic equivalent of the recent leak stuff?

@nrc

nrc May 15, 2015

Member

I feel like we should make some attempt at defining a soundness bug. Since we have no formal model, we are not using the formal definition here. Are soundness bugs limited to formal type soundness? Only bugs which affect Rust's major invariants. What about technically sound but unexpected behaviour from some language feature? A linguistic equivalent of the recent leak stuff?

This comment has been minimized.

@nikomatsakis

nikomatsakis May 20, 2015

Contributor

@nrc

I feel like we should make some attempt at defining a soundness bug.

yeah, I mentioned this in the unresolved questions. I'm not sure precisely how to define it. There are many things that are only unsound when unsafe code gets involved, for example, so this really comes down to deciding what unsafe code should or should not be able to do. That is a work-in-progress -- so I think we should approach this on a case-by-case basis, but use the debates over proposed breaking changes to feed back into the evolving document clarifying what is legal in unsafe code.

So essentially a breaking change is warranted if any of the following results:

  1. Ability to produce undefined behavior purely from safe code.
  2. Ability to produce undefined behavior using standard library APIs or other unsafe code that "should work" (which will be partly defined by the changes we choose to make or not make, as I said above).
@nikomatsakis

nikomatsakis May 20, 2015

Contributor

@nrc

I feel like we should make some attempt at defining a soundness bug.

yeah, I mentioned this in the unresolved questions. I'm not sure precisely how to define it. There are many things that are only unsound when unsafe code gets involved, for example, so this really comes down to deciding what unsafe code should or should not be able to do. That is a work-in-progress -- so I think we should approach this on a case-by-case basis, but use the debates over proposed breaking changes to feed back into the evolving document clarifying what is legal in unsafe code.

So essentially a breaking change is warranted if any of the following results:

  1. Ability to produce undefined behavior purely from safe code.
  2. Ability to produce undefined behavior using standard library APIs or other unsafe code that "should work" (which will be partly defined by the changes we choose to make or not make, as I said above).

This comment has been minimized.

@nikomatsakis

nikomatsakis May 20, 2015

Contributor

Ah, I thought of something I forgot here -- I think we want to include other kinds of type safety holes, such as coherence, which may not directly cause undefined behavior, but break other invariants we are trying to maintain (in the case of coherence, that crates can always be linked together).

@nikomatsakis

nikomatsakis May 20, 2015

Contributor

Ah, I thought of something I forgot here -- I think we want to include other kinds of type safety holes, such as coherence, which may not directly cause undefined behavior, but break other invariants we are trying to maintain (in the case of coherence, that crates can always be linked together).

text/0000-contingency-plan.md
+ and work with the crate author to correct the code as quickly as
+ possible, ideally before the fix even lands.
+2. Work hard to ensure that the error message identifies the problem
+ clearly and suggests the appropriate solution.

This comment has been minimized.

@nrc

nrc May 15, 2015

Member

This assumes that the fix is to introduce an error rather than a silent change in behaviour. That is obviously preferable, but perhaps there will be situations where it is not possible. How will we handle those?

@nrc

nrc May 15, 2015

Member

This assumes that the fix is to introduce an error rather than a silent change in behaviour. That is obviously preferable, but perhaps there will be situations where it is not possible. How will we handle those?

This comment has been minimized.

@nikomatsakis

nikomatsakis May 20, 2015

Contributor

@nrc

This assumes that the fix is to introduce an error rather than a silent change in behaviour. That is obviously preferable, but perhaps there will be situations where it is not possible. How will we handle those?

this is described in this section https://github.com/nikomatsakis/rfcs/blob/language-semver/text/0000-contingency-plan.md#changes-that-alter-dynamic-semantics-versus-typing-rules

@nikomatsakis

nikomatsakis May 20, 2015

Contributor

@nrc

This assumes that the fix is to introduce an error rather than a silent change in behaviour. That is obviously preferable, but perhaps there will be situations where it is not possible. How will we handle those?

this is described in this section https://github.com/nikomatsakis/rfcs/blob/language-semver/text/0000-contingency-plan.md#changes-that-alter-dynamic-semantics-versus-typing-rules

text/0000-contingency-plan.md
+ However, this option may frequently not be available, because the
+ source of a compilation error is often hard to pin down with
+ precision.
+

This comment has been minimized.

@nrc

nrc May 15, 2015

Member

We should attempt to supply a 'rustfix' tool specifically to fix these changes too. Given that this might be possible only in certain circumstances, we should specify how it affects the above steps.

@nrc

nrc May 15, 2015

Member

We should attempt to supply a 'rustfix' tool specifically to fix these changes too. Given that this might be possible only in certain circumstances, we should specify how it affects the above steps.

This comment has been minimized.

@nikomatsakis

nikomatsakis May 20, 2015

Contributor

@nrc

We should attempt to supply a 'rustfix' tool specifically to fix these changes too.

Interesting. Given that we have no such tool, it feels a bit premature, but I I think it falls under a strong version of point 2: rustfix would be equivalent to a very clear error message, and then a bit more. I'll edit something in.

@nikomatsakis

nikomatsakis May 20, 2015

Contributor

@nrc

We should attempt to supply a 'rustfix' tool specifically to fix these changes too.

Interesting. Given that we have no such tool, it feels a bit premature, but I I think it falls under a strong version of point 2: rustfix would be equivalent to a very clear error message, and then a bit more. I'll edit something in.

This comment has been minimized.

@nrc

nrc May 20, 2015

Member

I was thinking that we could write a specific tool (rather than a general purpose rustfix) which fixes specific fallout from a language change and we could make that available at the time of the announcement. Obviously that would not be feasible in many cases, but I imagine such a think could be knocked together in a few days in many cases.

@nrc

nrc May 20, 2015

Member

I was thinking that we could write a specific tool (rather than a general purpose rustfix) which fixes specific fallout from a language change and we could make that available at the time of the announcement. Obviously that would not be feasible in many cases, but I imagine such a think could be knocked together in a few days in many cases.

text/0000-contingency-plan.md
+3. Provide an annotation that allows for a scoped "opt out" of the
+ newer rules, as described below. While the change is still
+ breaking, this at least makes it easy for crates to update and get
+ back to compiling status quickly.

This comment has been minimized.

@nrc

nrc May 15, 2015

Member

This feels like it might be really hard and sometimes impossible in some cases. We should not guarantee it.

@nrc

nrc May 15, 2015

Member

This feels like it might be really hard and sometimes impossible in some cases. We should not guarantee it.

This comment has been minimized.

@nikomatsakis

nikomatsakis May 20, 2015

Contributor

@nrc

We should not guarantee it.

I did not mean to imply that we would guarantee any such thing. I'm just discussing possible measures we can employ, not all of which will be applicable to or necessary in any given scenario. I'll edit the text to make that clearer.

@nikomatsakis

nikomatsakis May 20, 2015

Contributor

@nrc

We should not guarantee it.

I did not mean to imply that we would guarantee any such thing. I'm just discussing possible measures we can employ, not all of which will be applicable to or necessary in any given scenario. I'll edit the text to make that clearer.

text/0000-contingency-plan.md
+- What changes are needed to get code compiling again? Are those
+ changes obvious from the error message?
+ - The more cryptic the error, the more frustrating it is when
+ compilation fails.

This comment has been minimized.

@nrc

nrc May 15, 2015

Member

Feels like we're missing something here on the magnitude of the affects of the error. Presumably an error which means Rust is totally memory unsafe would be treated more urgently than one which allowed public access to a private variable or something.

@nrc

nrc May 15, 2015

Member

Feels like we're missing something here on the magnitude of the affects of the error. Presumably an error which means Rust is totally memory unsafe would be treated more urgently than one which allowed public access to a private variable or something.

This comment has been minimized.

@nikomatsakis

nikomatsakis May 20, 2015

Contributor

@nrc

Feels like we're missing something here on the magnitude of the affects of the error.

Heh, good point.

@nikomatsakis

nikomatsakis May 20, 2015

Contributor

@nrc

Feels like we're missing something here on the magnitude of the affects of the error.

Heh, good point.

text/0000-contingency-plan.md
+rules. The intention is that this "opt out" is used as a temporary
+crutch to make it easy to get the code up and running. Depending on
+the severity of the soundness fix, the "opt out" may be permanently
+available, or it could be removed in a later release. In either case,

This comment has been minimized.

@nrc

nrc May 15, 2015

Member

A "permanently available" soundness hole sounds very bad to me. I can't imagine why we'd allow it to remain. The more severe the hole, the more it should be fixed. And the more motivation for tool support to help fix it.

@nrc

nrc May 15, 2015

Member

A "permanently available" soundness hole sounds very bad to me. I can't imagine why we'd allow it to remain. The more severe the hole, the more it should be fixed. And the more motivation for tool support to help fix it.

This comment has been minimized.

@nikomatsakis

nikomatsakis May 20, 2015

Contributor

@nrc

A "permanently available" soundness hole sounds very bad to me.

I agree, I was envisioning primarily "less dangerous" kinds of soundness holds, such as bugs in coherence that could lead to overlapping impls. I'll rework the text though to make it clear that "permanently available" changes would be the exception.

@nikomatsakis

nikomatsakis May 20, 2015

Contributor

@nrc

A "permanently available" soundness hole sounds very bad to me.

I agree, I was envisioning primarily "less dangerous" kinds of soundness holds, such as bugs in coherence that could lead to overlapping impls. I'll rework the text though to make it clear that "permanently available" changes would be the exception.

text/0000-contingency-plan.md
+- The treatment of hygiene in macros is uneven (see [#22462], [#24278]). In some cases,
+ changes here may be backwards compatible, or may be more appropriate only with explicit opt-in
+ (or perhaps an alternate macro system altogether).
+- The layout of data structures is expected to change over time unless they are annotated

This comment has been minimized.

@nrc

nrc May 15, 2015

Member

This does not feel underspecifed to me. The specification is precise and complete - if you're not using #[repr(C)] the compiler can do what it likes with data layout and you cannot rely on it.

@nrc

nrc May 15, 2015

Member

This does not feel underspecifed to me. The specification is precise and complete - if you're not using #[repr(C)] the compiler can do what it likes with data layout and you cannot rely on it.

text/0000-contingency-plan.md
+passing that some of the CLI flags to the compiler may change in the
+future as well. The `-Z` flags are of course explicitly unstable, but
+some of the `-C`, rustdoc, and linker-specific flags are expected to
+evolve over time.)

This comment has been minimized.

@nrc

nrc May 15, 2015

Member

Would be good to specify how these will affect semver

@nrc

nrc May 15, 2015

Member

Would be good to specify how these will affect semver

text/0000-contingency-plan.md
+semantics, but are still deemed desirable, an opt-in strategy can be
+used instead. This section describes an attribute for opting in to
+newer language updates, and gives guidelines on what kinds of changes
+should or should not be introduced in this fashion.

This comment has been minimized.

@nrc

nrc May 15, 2015

Member

Again, presumably this is just covering what happens until we bump the major version number?

@nrc

nrc May 15, 2015

Member

Again, presumably this is just covering what happens until we bump the major version number?

text/0000-contingency-plan.md
+newer version the compiler knows about).
+
+Note that if the changes introducing by the Rust version `X.Y` affect
+parsing, implementing these semantics may require some limited amount

This comment has been minimized.

@nrc

nrc May 15, 2015

Member

This is getting scary - in particular, how will this interact with syntax extensions? I mean we need to figure out what the compatibility story will be with syntax extensions before we stabilise them. But this seems like saying there is no guarantee at all about what the token stream/AST will contain.

@nrc

nrc May 15, 2015

Member

This is getting scary - in particular, how will this interact with syntax extensions? I mean we need to figure out what the compatibility story will be with syntax extensions before we stabilise them. But this seems like saying there is no guarantee at all about what the token stream/AST will contain.

This comment has been minimized.

@nikomatsakis

nikomatsakis May 20, 2015

Contributor

@nrc

Well, I guess that would depend a lot on the interface to syntax extensions, right? But I imagine that syntax extensions take as input token trees that do not differentiate keywords (after all, macro-rules definitions can insert arbitrary keywords, for example). If you were to use a $t:expr (or $t:ty etc) fragment, then of course the current Rust version would be relevant, but for raw token trees it is not. But this of course raises the question of the best syntax extension interface, which I know has somewhat debated :)

@nikomatsakis

nikomatsakis May 20, 2015

Contributor

@nrc

Well, I guess that would depend a lot on the interface to syntax extensions, right? But I imagine that syntax extensions take as input token trees that do not differentiate keywords (after all, macro-rules definitions can insert arbitrary keywords, for example). If you were to use a $t:expr (or $t:ty etc) fragment, then of course the current Rust version would be relevant, but for raw token trees it is not. But this of course raises the question of the best syntax extension interface, which I know has somewhat debated :)

text/0000-contingency-plan.md
+
+**Rather than using a version number to opt-in to minor changes, one
+might consider using the existing feature mechanism.** For example,
+one could write `#![feature(foo)]` to opt in to the feature "foo" and

This comment has been minimized.

@nrc

nrc May 15, 2015

Member

+1 for this alternative as mentioned above

@nrc

nrc May 15, 2015

Member

+1 for this alternative as mentioned above

text/0000-contingency-plan.md
+
+1. Using a version number alone makes it easy to think about what
+ version of Rust you are using as a conceptual unit, rather than
+ choosing features "a la carte".

This comment has been minimized.

@nrc

nrc May 15, 2015

Member

Why do we want to encourage this thinking? If we thought that some set of features was coherent and major enough to always use together, we should issue a new major version

@nrc

nrc May 15, 2015

Member

Why do we want to encourage this thinking? If we thought that some set of features was coherent and major enough to always use together, we should issue a new major version

This comment has been minimized.

@nikomatsakis

nikomatsakis May 20, 2015

Contributor

@nrc

If we thought that some set of features was coherent and major enough to always use together, we should issue a new major version

I think that the set of features should always be consistent and major enough to use together at all times? I'm not really sure what "to use together" means, I guess, I'm not sure why you would not use them together.

I feel like major versions are a way of signalling that we removed deprecating things, or we made other "lateral" changes that are not additive nor bug fixes (certainly that's the intention of this RFC).

@nikomatsakis

nikomatsakis May 20, 2015

Contributor

@nrc

If we thought that some set of features was coherent and major enough to always use together, we should issue a new major version

I think that the set of features should always be consistent and major enough to use together at all times? I'm not really sure what "to use together" means, I guess, I'm not sure why you would not use them together.

I feel like major versions are a way of signalling that we removed deprecating things, or we made other "lateral" changes that are not additive nor bug fixes (certainly that's the intention of this RFC).

text/0000-contingency-plan.md
+ choosing features "a la carte".
+2. Using named features, the list of features that must be attached to
+ Rust code will grow indefinitely, presuming your crate wants to
+ stay up to date.

This comment has been minimized.

@nrc

nrc May 15, 2015

Member

I hope we don't have so many opt-in features between major versions that this becomes a problem

@nrc

nrc May 15, 2015

Member

I hope we don't have so many opt-in features between major versions that this becomes a problem

This comment has been minimized.

@nikomatsakis

nikomatsakis May 20, 2015

Contributor

@nrc

I hope we don't have so many opt-in features between major versions that this becomes a problem

I guess that will depend on how frequently we issue major versions.

@nikomatsakis

nikomatsakis May 20, 2015

Contributor

@nrc

I hope we don't have so many opt-in features between major versions that this becomes a problem

I guess that will depend on how frequently we issue major versions.

This comment has been minimized.

@nikomatsakis

nikomatsakis May 20, 2015

Contributor

@nrc

I hope we don't have so many opt-in features between major versions that this becomes a problem

To expound a bit here, I do think that if we start to accumulate a lot of opt-in changes, it's probably a sign that it's time for a new major version. Using feature names rather than version numbers makes that pressure more obvious, which could be seen as an argument either for or against it.

@nikomatsakis

nikomatsakis May 20, 2015

Contributor

@nrc

I hope we don't have so many opt-in features between major versions that this becomes a problem

To expound a bit here, I do think that if we start to accumulate a lot of opt-in changes, it's probably a sign that it's time for a new major version. Using feature names rather than version numbers makes that pressure more obvious, which could be seen as an argument either for or against it.

text/0000-contingency-plan.md
+ Rust code will grow indefinitely, presuming your crate wants to
+ stay up to date.
+3. Using a version attribute preserves a mental separation between
+ "experimental work" (feature gates) and stable, new features.

This comment has been minimized.

@nrc

nrc May 15, 2015

Member

The fact that a feature can be used on beta/release branches means that it is stable.

@nrc

nrc May 15, 2015

Member

The fact that a feature can be used on beta/release branches means that it is stable.

This comment has been minimized.

@nikomatsakis

nikomatsakis May 20, 2015

Contributor

@nrc

The fact that a feature can be used on beta/release branches means that it is stable.

Sure, but I can see that people might want to use nightly simply to get acccess to bug fixes and so forth faster, but wouldn't want to rely on unstable features. Knowing that "#[feature] means unstable" makes it easier to audit. Admittedly, probably not too hard either way, but that's what I meant by "mental separation". It's not about what branch you're on.

@nikomatsakis

nikomatsakis May 20, 2015

Contributor

@nrc

The fact that a feature can be used on beta/release branches means that it is stable.

Sure, but I can see that people might want to use nightly simply to get acccess to bug fixes and so forth faster, but wouldn't want to rely on unstable features. Knowing that "#[feature] means unstable" makes it easier to audit. Admittedly, probably not too hard either way, but that's what I meant by "mental separation". It's not about what branch you're on.

text/0000-contingency-plan.md
+ "experimental work" (feature gates) and stable, new features.
+4. Named features present a combinatoric testing problem, where we
+ should (in principle) test for all possible combinations of
+ features.

This comment has been minimized.

@nrc

nrc May 15, 2015

Member

This seems the most important point and hard to argue against. I guess I can only hope that opt-in features are rare enough that this won't be a problem. How many are you envisaging between major versions?

@nrc

nrc May 15, 2015

Member

This seems the most important point and hard to argue against. I guess I can only hope that opt-in features are rare enough that this won't be a problem. How many are you envisaging between major versions?

text/0000-contingency-plan.md
+constitutes a compiler bug and soundness change. It may be worth
+defining more precisely, though likely this would be best done as part
+of writing up a more thorough (and authoritative) Rust reference
+manual.

This comment has been minimized.

@nrc

nrc May 15, 2015

Member

Yes, we should :-) I don't think it needs to be super formal, but some guidance would be useful.

@nrc

nrc May 15, 2015

Member

Yes, we should :-) I don't think it needs to be super formal, but some guidance would be useful.

text/0000-contingency-plan.md
+breaking change for your clients, which you may not wish to do. If we
+had an escaping mechanism, you would probably still want to deprecate
+`foo` in favor of a new function `bar` (since typing `foo` would be
+awkward), but it could still exist.

This comment has been minimized.

@nrc

nrc May 15, 2015

Member

This seems so easy to fix with a refactoring tool that it should be unnecessary.

@nrc

nrc May 15, 2015

Member

This seems so easy to fix with a refactoring tool that it should be unnecessary.

This comment has been minimized.

@nikomatsakis

nikomatsakis May 20, 2015

Contributor

@nrc

This seems so easy to fix with a refactoring tool that it should be unnecessary.

I don't follow. Point is, if I update my compiler and rename my methods, I break my clients and force them to refactor. Maybe your point is: that's acceptable, because we can have a tool that renames functions from match to match_ or something? (we may itself introduce conflicts...)

@nikomatsakis

nikomatsakis May 20, 2015

Contributor

@nrc

This seems so easy to fix with a refactoring tool that it should be unnecessary.

I don't follow. Point is, if I update my compiler and rename my methods, I break my clients and force them to refactor. Maybe your point is: that's acceptable, because we can have a tool that renames functions from match to match_ or something? (we may itself introduce conflicts...)

This comment has been minimized.

@nrc

nrc May 20, 2015

Member

I was thinking a combination of: it is not so important for downstream libs to break there clients because they can bump their semver major version easily without breaking their downstream deps thanks to Cargo. And it is easy for their downstream libs to adjust to the change thanks to the refactoring tool (I'm envisaging having some kind of script for a refactoring tool and the commit message or new version announcment or something includes a refactoring script for the name change).

Conflicts would make this harder, but if we have good refactoring support, then not too much harder.

@nrc

nrc May 20, 2015

Member

I was thinking a combination of: it is not so important for downstream libs to break there clients because they can bump their semver major version easily without breaking their downstream deps thanks to Cargo. And it is easy for their downstream libs to adjust to the change thanks to the refactoring tool (I'm envisaging having some kind of script for a refactoring tool and the commit message or new version announcment or something includes a refactoring script for the name change).

Conflicts would make this harder, but if we have good refactoring support, then not too much harder.

This comment has been minimized.

@nikomatsakis

nikomatsakis May 21, 2015

Contributor

well, I'm just presuming that downstream libs will not necessarily want to bump their major version number just to gain access to a new keyword internally, but I agree that we could possibly just not provide a way to escape and live with it.

@nikomatsakis

nikomatsakis May 21, 2015

Contributor

well, I'm just presuming that downstream libs will not necessarily want to bump their major version number just to gain access to a new keyword internally, but I agree that we could possibly just not provide a way to escape and live with it.

text/0000-contingency-plan.md
+over sections of the input (presumably based on token trees). One
+approach to this might just be modifying the existing `#[cfg]`
+directives so that they are applied during parsing rather than as a
+post-pass.

This comment has been minimized.

@nrc

nrc May 15, 2015

Member

I've long wanted to make cfg token tree based.

@nrc

nrc May 15, 2015

Member

I've long wanted to make cfg token tree based.

text/0000-contingency-plan.md
+stable Rust, this has the unfortunate side-effect of meaning that code
+which opts out of the newer rules cannot be compiled on older
+compilers (even though it's using the older type system rules). If we
+introduce an attribute in advance we will not have this problem.

This comment has been minimized.

@nrc

nrc May 15, 2015

Member

We've talked about scoped attributes before, it seems like we could take advantage of that here. It does have the backwards compatibility issue, but only once, not for every attribute.

@nrc

nrc May 15, 2015

Member

We've talked about scoped attributes before, it seems like we could take advantage of that here. It does have the backwards compatibility issue, but only once, not for every attribute.

@@ -0,0 +1,425 @@
+- Feature Name: N/A

This comment has been minimized.

@nrc

nrc May 15, 2015

Member

Is this file meant to be included? It seems like an early version of the other one.

@nrc

nrc May 15, 2015

Member

Is this file meant to be included? It seems like an early version of the other one.

This comment has been minimized.

@nikomatsakis

nikomatsakis May 20, 2015

Contributor

Probably not. :)

@nikomatsakis

nikomatsakis May 20, 2015

Contributor

Probably not. :)

@nrc nrc added the T-lang label May 15, 2015

text/0000-contingency-plan.md
+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**.

This comment has been minimized.

@seanmonstar

seanmonstar May 15, 2015

Contributor

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.

@seanmonstar

seanmonstar May 15, 2015

Contributor

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.

This comment has been minimized.

@nikomatsakis

nikomatsakis May 20, 2015

Contributor

@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...

@nikomatsakis

nikomatsakis May 20, 2015

Contributor

@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...

@nikomatsakis nikomatsakis changed the title from Semantic versioning for the language to RFC: Semantic versioning for the language May 19, 2015

@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis May 21, 2015

Contributor

I just pushed a new version which addresses some suggestions, but not (yet) the suggestion to use a command-line option.

Contributor

nikomatsakis commented May 21, 2015

I just pushed a new version which addresses some suggestions, but not (yet) the suggestion to use a command-line option.

@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis May 21, 2015

Contributor

@alexcrichton I added some text about using rust-version as a command-line option, though many of the details I put down kind of stray into "tools" domain I would say. I didn't include the attribute. Happy to debate it. :)

Contributor

nikomatsakis commented May 21, 2015

@alexcrichton I added some text about using rust-version as a command-line option, though many of the details I put down kind of stray into "tools" domain I would say. I didn't include the attribute. Happy to debate it. :)

@tshepang

This comment has been minimized.

Show comment
Hide comment
@tshepang

tshepang May 21, 2015

That is not too readable. Maybe something like:

This RFC proposes that breaking changes be permitted in minor releases only if they fix soundless issues.

That is not too readable. Maybe something like:

This RFC proposes that breaking changes be permitted in minor releases only if they fix soundless issues.

@tshepang

This comment has been minimized.

Show comment
Hide comment
@tshepang

tshepang May 21, 2015

This is also not so readable. Maybe:

This includes:

  • bug fixes in the compiler
  • changes to the type system
  • flaws that are uncovered later

This is also not so readable. Maybe:

This includes:

  • bug fixes in the compiler
  • changes to the type system
  • flaws that are uncovered later
@tshepang

This comment has been minimized.

Show comment
Hide comment
@tshepang

tshepang May 21, 2015

s/betwen/between

s/betwen/between

text/0000-language-semver.md
+precisely constitutes a "minor" vs "major" change to the Rust language
+itself (as opposed to libraries, which are covered by [RFC 1105]).
+**This RFC proposes that breaking changes are only permitted within a
+minor release if they are fix to restore soundness**: this includes

This comment has been minimized.

@pnkfelix

pnkfelix May 21, 2015

Member

typo: "are fixes to"

@pnkfelix

pnkfelix May 21, 2015

Member

typo: "are fixes to"

text/0000-language-semver.md
+
+# Detailed design
+
+The detailed design is broken into two major section: how to address

This comment has been minimized.

@pnkfelix

pnkfelix May 21, 2015

Member

typo: two major sections

@pnkfelix

pnkfelix May 21, 2015

Member

typo: two major sections

@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis May 22, 2015

Contributor

@larsbergstrom

I was a little surprised not to see anything about changes to the borrow check algorithm mentioned.

These seem like straight-up soundness changes? I'm happy to call borrowck out explicitly, but I think all of the changes that have caused you problems were changes that were known to break code, and we're done to close up a hole somewhere or other (usually with efforts to minimize the breakage as best we could).

Contributor

nikomatsakis commented May 22, 2015

@larsbergstrom

I was a little surprised not to see anything about changes to the borrow check algorithm mentioned.

These seem like straight-up soundness changes? I'm happy to call borrowck out explicitly, but I think all of the changes that have caused you problems were changes that were known to break code, and we're done to close up a hole somewhere or other (usually with efforts to minimize the breakage as best we could).

@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis May 22, 2015

Contributor

I'd like to move this RFC into the final comment period starting next week, mostly because I think it lays important groundwork for deciding on upcoming PRs, changes, etc.

If I'm not mistaken, the only major question that has been raised is whether to use version numbers or attribute tags (by @nrc). @nrc, I'm not sure how strong your objection is here -- I think on balance I still prefer version numbers, for the reasons elaborated in the RFC (and they seem to fit better with the current framing of the RFC, in which version numbers are given on the rustc command line versus in the source feel). It'd probably be helpful to get the opinions of others on record in this respect. But it seems like settling this aspect is the major step we need to take before we can move to FCP.

cc @rust-lang/lang

Contributor

nikomatsakis commented May 22, 2015

I'd like to move this RFC into the final comment period starting next week, mostly because I think it lays important groundwork for deciding on upcoming PRs, changes, etc.

If I'm not mistaken, the only major question that has been raised is whether to use version numbers or attribute tags (by @nrc). @nrc, I'm not sure how strong your objection is here -- I think on balance I still prefer version numbers, for the reasons elaborated in the RFC (and they seem to fit better with the current framing of the RFC, in which version numbers are given on the rustc command line versus in the source feel). It'd probably be helpful to get the opinions of others on record in this respect. But it seems like settling this aspect is the major step we need to take before we can move to FCP.

cc @rust-lang/lang

+changes, because the unsafe code is relying on things known to be
+intentionally unspecified. One obvious example is the layout of data
+structures, which is considered undefined unless they have a
+`#[repr(C)]` attribute.

This comment has been minimized.

@pnkfelix

pnkfelix May 22, 2015

Member

... I revisited this paragraph while reviewing the dialogue between @nikomatsakis and @nrc ; I don't know whether it's worth spelling this out explicitly, but it sounds to me like one should conclude from this paragraph that minor versions of Rust can freely break uses of mem::transmute::<S, T> where S or T lacks a #[repr(C)].

(By "freely break", I mean that the rustc upgrade can inject either compilation errors or differences in runtime behavior, included undefined behavior...)

Is that a correct reading of the text? If so, is it worth pointing out explicitly?

Update: the above conclusion may be a little too strong, I am not sure. It certainly seems like we can freely inject compilation errors (due to size_of changing for S or T). But certain combinations of S and T might well be defined as "guaranteed to work" even without a repr(C) ... again, not sure if that is worth spelling out explicitly either.

@pnkfelix

pnkfelix May 22, 2015

Member

... I revisited this paragraph while reviewing the dialogue between @nikomatsakis and @nrc ; I don't know whether it's worth spelling this out explicitly, but it sounds to me like one should conclude from this paragraph that minor versions of Rust can freely break uses of mem::transmute::<S, T> where S or T lacks a #[repr(C)].

(By "freely break", I mean that the rustc upgrade can inject either compilation errors or differences in runtime behavior, included undefined behavior...)

Is that a correct reading of the text? If so, is it worth pointing out explicitly?

Update: the above conclusion may be a little too strong, I am not sure. It certainly seems like we can freely inject compilation errors (due to size_of changing for S or T). But certain combinations of S and T might well be defined as "guaranteed to work" even without a repr(C) ... again, not sure if that is worth spelling out explicitly either.

@pnkfelix

This comment has been minimized.

Show comment
Hide comment
@pnkfelix

pnkfelix May 22, 2015

Member

I was originally in favor of feature names (i.e. "attribute tags", though I think they should be in the command line interface, not #![attributes]). Now I'm mostly on the fence about it, and tilting towards the side of version numbers largely due to the combinatorial explosion of tests issue.

Member

pnkfelix commented May 22, 2015

I was originally in favor of feature names (i.e. "attribute tags", though I think they should be in the command line interface, not #![attributes]). Now I'm mostly on the fence about it, and tilting towards the side of version numbers largely due to the combinatorial explosion of tests issue.

@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis May 22, 2015

Contributor

@wycats I'd like to get your take on the language versioning aspect of this RFC as well, since I know that you've thought about this a fair amount in terms of cargo.

Contributor

nikomatsakis commented May 22, 2015

@wycats I'd like to get your take on the language versioning aspect of this RFC as well, since I know that you've thought about this a fair amount in terms of cargo.

@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis May 22, 2015

Contributor

Some thoughts that were discussed over IRC:

  1. The version number can also be useful in terms of signaling library requirements. There were other thoughts on ways to do this, such as automatic "feature" detection.
  2. Version numbers could be used to warn about use of APIs that were not stable "as of" the declared version.
  3. I do have some concerns (which I expressed on IRC) that using the Rust version numbers from our releases will lead to a wide variety of "random" version numbers out there in Cargo, which might in turn lead to a lot of annoyance where people try to pick the lowest version number that meets their requirements, or consolidate on version numbers where "major changes" occurred.
  4. In some sense, declaring features may help here, but I still find it unappealing, for the reasons I cited. (As well as a kind of gut feeling that declaring features leads to a mindset of "I am using Rust plus these optional features" which, to me, doesn't feel as good as "I am using Rust 1.6".)
Contributor

nikomatsakis commented May 22, 2015

Some thoughts that were discussed over IRC:

  1. The version number can also be useful in terms of signaling library requirements. There were other thoughts on ways to do this, such as automatic "feature" detection.
  2. Version numbers could be used to warn about use of APIs that were not stable "as of" the declared version.
  3. I do have some concerns (which I expressed on IRC) that using the Rust version numbers from our releases will lead to a wide variety of "random" version numbers out there in Cargo, which might in turn lead to a lot of annoyance where people try to pick the lowest version number that meets their requirements, or consolidate on version numbers where "major changes" occurred.
  4. In some sense, declaring features may help here, but I still find it unappealing, for the reasons I cited. (As well as a kind of gut feeling that declaring features leads to a mindset of "I am using Rust plus these optional features" which, to me, doesn't feel as good as "I am using Rust 1.6".)
@nrc

This comment has been minimized.

Show comment
Hide comment
@nrc

nrc May 23, 2015

Member

@nikomatsakis I am mostly persuaded by the arguments for version numbers. Something nags at me, I think about having named features before they're stable and numbered versions once things become stable. But perhaps that is OK, and is part of the distinction between stable and unstable features.

As it stands, I'm happy for the RFC to progress with numbers rather than named features.

Member

nrc commented May 23, 2015

@nikomatsakis I am mostly persuaded by the arguments for version numbers. Something nags at me, I think about having named features before they're stable and numbered versions once things become stable. But perhaps that is OK, and is part of the distinction between stable and unstable features.

As it stands, I'm happy for the RFC to progress with numbers rather than named features.

@sfackler

This comment has been minimized.

Show comment
Hide comment
@sfackler

sfackler May 23, 2015

Member

One other benefit of providing a target version to the compiler is that it can allow the compiler to suppress deprecation warnings for APIs that were deprecated in versions after the target (at least for "you should instead use API x that was just introduced" style deprecations).

Member

sfackler commented May 23, 2015

One other benefit of providing a target version to the compiler is that it can allow the compiler to suppress deprecation warnings for APIs that were deprecated in versions after the target (at least for "you should instead use API x that was just introduced" style deprecations).

text/0000-language-semver.md
+defaults to this builtin version.
+
+The supplied version is used by the compiler to produce the semantics
+of Rust "as it was" during version `X.Y`. RFCs that propose opt-in

This comment has been minimized.

@huonw

huonw May 24, 2015

Member

Hm, I'm not sure I understand this opt-in discussion. Is the hypothetical scenario building a crate that uses an opt-in feature from rust 1.2, but passing, say, --rust-version=1.1? If so, I don't see how this makes sense (why would one be opting-in to a version of Rust that can't handle the stuff the code uses?).

@huonw

huonw May 24, 2015

Member

Hm, I'm not sure I understand this opt-in discussion. Is the hypothetical scenario building a crate that uses an opt-in feature from rust 1.2, but passing, say, --rust-version=1.1? If so, I don't see how this makes sense (why would one be opting-in to a version of Rust that can't handle the stuff the code uses?).

This comment has been minimized.

@nikomatsakis

nikomatsakis May 26, 2015

Contributor

@huonw

Is the hypothetical scenario building a crate that uses an opt-in feature from rust 1.2, but passing, say, --rust-version=1.1?

No, that would just yield compilation errors I imagine. The scenario is primarily about keeping old code written in the 1.1 days compiling, even though we added keywords in 1.2 that would make it (e.g.) fail to parse. But there are other relevant criteria too, such as libraries, that @sfackler has been pointing out, where you might encounter similar situations (that is, at some point we'll probably have crates that want to ensure that they can continue to be compile with earlier versions of Rust, and hence which want to avoid newer APIs).

@nikomatsakis

nikomatsakis May 26, 2015

Contributor

@huonw

Is the hypothetical scenario building a crate that uses an opt-in feature from rust 1.2, but passing, say, --rust-version=1.1?

No, that would just yield compilation errors I imagine. The scenario is primarily about keeping old code written in the 1.1 days compiling, even though we added keywords in 1.2 that would make it (e.g.) fail to parse. But there are other relevant criteria too, such as libraries, that @sfackler has been pointing out, where you might encounter similar situations (that is, at some point we'll probably have crates that want to ensure that they can continue to be compile with earlier versions of Rust, and hence which want to avoid newer APIs).

@DanielKeep

This comment has been minimized.

Show comment
Hide comment
@DanielKeep

DanielKeep May 27, 2015

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...)

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

This comment has been minimized.

Show comment
Hide comment
@comex

comex 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

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

This comment has been minimized.

Show comment
Hide comment
@glaebhoerl

glaebhoerl May 28, 2015

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. ;)

Contributor

glaebhoerl commented May 28, 2015

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

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis May 28, 2015

Contributor

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.

Contributor

nikomatsakis commented May 28, 2015

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

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis May 28, 2015

Contributor

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.
Contributor

nikomatsakis commented May 28, 2015

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

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis Jun 3, 2015

Contributor

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

Contributor

nikomatsakis commented Jun 3, 2015

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

@llogiq

This comment has been minimized.

Show comment
Hide comment
@llogiq

llogiq Jun 5, 2015

Contributor

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.

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

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis Jun 10, 2015

Contributor

@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).

Contributor

nikomatsakis commented Jun 10, 2015

@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

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis Jun 10, 2015

Contributor

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.

Contributor

nikomatsakis commented Jun 10, 2015

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

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis Jun 10, 2015

Contributor

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

Contributor

nikomatsakis commented Jun 10, 2015

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

Adjust policy text to include warnings in 1.2, hard error in 1.3,
and remove the legacy attribute (also adjust text of RFC #1122 slightly).

nikomatsakis added a commit to nikomatsakis/rfcs that referenced this pull request Jun 16, 2015

@leodasvacas leodasvacas referenced this pull request Jun 3, 2016

Merged

Minimal `impl Trait` #1522

@chriskrycho chriskrycho referenced this pull request in rust-lang/rust Feb 8, 2017

Closed

Document all features in the reference #38643

0 of 17 tasks complete

@chriskrycho chriskrycho referenced this pull request in rust-lang-nursery/reference Mar 11, 2017

Closed

Document all features #9

18 of 48 tasks complete
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment