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: Evolving Rust through Epochs #2052

Merged
merged 16 commits into from Sep 14, 2017

Conversation

@aturon
Member

aturon commented Jul 3, 2017

Rust's ecosystem, tooling, documentation, and compiler are constantly improving. To make it easier to follow development, and to provide a clear, coherent "rallying point" for this work, this RFC proposes that we declare a epoch every two or three years. Epochs are designated by the year in which they occur, and represent a release in which several elements come together:

  • A significant, coherent set of new features and APIs have been stabilized since the previous epoch.
  • Error messages and other important aspects of the user experience around these features are fully polished.
  • Tooling (IDEs, rustfmt, Clippy, etc) has been updated to work properly with these new features.
  • There is a guide to the new features, explaining why they're important and how they should influence the way you write Rust code.
  • The book has been updated to cover the new features.
    • Note that this is already required prior to stabilization, but in general these additions are put in an appendix; updating the book itself requires significant work, because new features can change the book in deep and cross-cutting ways. We don't block stabilization on that.
  • The standard library and other core ecosystem crates have been updated to use the new features as appropriate.
  • A new edition of the Rust Cookbook has been prepared, providing an updated set of guidance for which crates to use for various tasks.

Sometimes a feature we want to make available in a new epoch would require backwards-incompatible changes, like introducing a new keyword. In that case, the feature is only available by explicitly opting in to the new epoch. Existing code continues to compile, and crates can freely mix dependencies using different epochs.

Rendered

Update: there's a Request for Explanation podcast episode about this RFC, which is a good way to quickly get up to speed!

Edit: fixed rendered link

@aturon aturon added the T-core label Jul 3, 2017

@aturon aturon self-assigned this Jul 3, 2017

@aturon

This comment has been minimized.

Show comment
Hide comment
@aturon

aturon Jul 3, 2017

Member

People may be interested to review a recent draft from the C++ world, C++ Stability, Velocity, and Deployment Plans, which tries to clarify plans around C++'s evolution and has many similarities with this RFC.

Member

aturon commented Jul 3, 2017

People may be interested to review a recent draft from the C++ world, C++ Stability, Velocity, and Deployment Plans, which tries to clarify plans around C++'s evolution and has many similarities with this RFC.

@steveklabnik

This comment has been minimized.

Show comment
Hide comment
@steveklabnik

steveklabnik Jul 3, 2017

Member

I have long been advocating for a "never Rust 2.0", and I see this RFC as reaffirming our commitment to stability.

I can't tell the future, of course, but for me, this RFC is the nail in the ⚰️ . No Rust 2.0! ❣️

Member

steveklabnik commented Jul 3, 2017

I have long been advocating for a "never Rust 2.0", and I see this RFC as reaffirming our commitment to stability.

I can't tell the future, of course, but for me, this RFC is the nail in the ⚰️ . No Rust 2.0! ❣️

@est31

This comment has been minimized.

Show comment
Hide comment
@est31

est31 Jul 3, 2017

Contributor

I came to Rust because it was stable, and value stability greatly. If this RFC means that I don't have to suffer from the new module system but can continue to use the current, magnificent one, I'm a great supporter!

Contributor

est31 commented Jul 3, 2017

I came to Rust because it was stable, and value stability greatly. If this RFC means that I don't have to suffer from the new module system but can continue to use the current, magnificent one, I'm a great supporter!

@steveklabnik

This comment has been minimized.

Show comment
Hide comment
@steveklabnik

steveklabnik Jul 3, 2017

Member

I don't have to suffer from the new module system but can continue to use the current, magnificent one,

To be clear, there isn't a module system proposal yet 😉

Member

steveklabnik commented Jul 3, 2017

I don't have to suffer from the new module system but can continue to use the current, magnificent one,

To be clear, there isn't a module system proposal yet 😉

@cmr

This comment has been minimized.

Show comment
Hide comment
@cmr

cmr Jul 3, 2017

Member

(amusingly, I was just complaining about the lack of this exact feature and philosophy in the OPLSS chat)

Member

cmr commented Jul 3, 2017

(amusingly, I was just complaining about the lack of this exact feature and philosophy in the OPLSS chat)

@SimonSapin

This comment has been minimized.

Show comment
Hide comment
@SimonSapin

SimonSapin Jul 3, 2017

Contributor

ATCs, impl Trait, and specialization all becoming available […] 2018

Be careful what things you put in the same sentence, it could sound like a promise ;)

Contributor

SimonSapin commented Jul 3, 2017

ATCs, impl Trait, and specialization all becoming available […] 2018

Be careful what things you put in the same sentence, it could sound like a promise ;)

@cuviper

This comment has been minimized.

Show comment
Hide comment
@cuviper

cuviper Jul 3, 2017

Member

Will all newly-stabilized features only go into the current epoch? There could be some new things that would be perfectly fine on the older epochs too. My gut says to only push forward, but I could imagine some cases might be harder to try and isolate their implementations.

Is it a semver-breaking change for a crate to start requiring a new epoch? Bumping rustc requirements at all was controversial in #1619.

Will cargo new always default to the newest epoch right away?

Member

cuviper commented Jul 3, 2017

Will all newly-stabilized features only go into the current epoch? There could be some new things that would be perfectly fine on the older epochs too. My gut says to only push forward, but I could imagine some cases might be harder to try and isolate their implementations.

Is it a semver-breaking change for a crate to start requiring a new epoch? Bumping rustc requirements at all was controversial in #1619.

Will cargo new always default to the newest epoch right away?

@Ixrec

This comment has been minimized.

Show comment
Hide comment
@Ixrec

Ixrec Jul 3, 2017

Contributor

Rust compilers are expected to support multiple epochs, and a crate dependency graph may involve several different epochs simultaneously. Thus, epochs do not split the ecosystem nor do they break existing code.

existing deprecations may turn into hard errors ... This is the only kind of change a new epoch can make.

the RFC proposes to limit epochal changes to be "superficial", i.e. occurring purely in the early front-end stages of the compiler

That answers every single question and concern I had about epochs in exactly the way I hoped they'd be answered, and even the parts of this RFC that I was not expecting (e.g. epoch previews) make perfect sense. +1000. Let's do this.

Though it might be worth explicitly stating that the pretty graph with green and orange bars is not committing us to actually creating those specific epochs at those specific future dates.

Contributor

Ixrec commented Jul 3, 2017

Rust compilers are expected to support multiple epochs, and a crate dependency graph may involve several different epochs simultaneously. Thus, epochs do not split the ecosystem nor do they break existing code.

existing deprecations may turn into hard errors ... This is the only kind of change a new epoch can make.

the RFC proposes to limit epochal changes to be "superficial", i.e. occurring purely in the early front-end stages of the compiler

That answers every single question and concern I had about epochs in exactly the way I hoped they'd be answered, and even the parts of this RFC that I was not expecting (e.g. epoch previews) make perfect sense. +1000. Let's do this.

Though it might be worth explicitly stating that the pretty graph with green and orange bars is not committing us to actually creating those specific epochs at those specific future dates.

@aatxe

This comment has been minimized.

Show comment
Hide comment
@aatxe

aatxe Jul 3, 2017

Member

Screenshot of CMR asking for this feature

Evidence of @cmr lamenting this missing feature.

Member

aatxe commented Jul 3, 2017

Screenshot of CMR asking for this feature

Evidence of @cmr lamenting this missing feature.

@Ixrec

This comment has been minimized.

Show comment
Hide comment
@Ixrec

Ixrec Jul 3, 2017

Contributor

@cuviper The cargo question is answered explicitly in the RFC:

cargo new will produce a Cargo.toml with the latest epoch value, including -preview epochs when applicable.

The semver one less explicitly, but I believe it's very strongly implied by this quote that there is no such thing as "requiring" an epoch and merely using a new epoch in your crate won't break any client code:

To be crystal clear: Rust compilers are expected to support multiple epochs, and a crate dependency graph may involve several different epochs simultaneously. Thus, epochs do not split the ecosystem nor do they break existing code.

But it wouldn't hurt to be even more crystal clear and say "there is no such thing as 'requiring' a minimum epoch of client code, only requiring minimum rustc/cargo versions" assuming I am interpreting this right.

Contributor

Ixrec commented Jul 3, 2017

@cuviper The cargo question is answered explicitly in the RFC:

cargo new will produce a Cargo.toml with the latest epoch value, including -preview epochs when applicable.

The semver one less explicitly, but I believe it's very strongly implied by this quote that there is no such thing as "requiring" an epoch and merely using a new epoch in your crate won't break any client code:

To be crystal clear: Rust compilers are expected to support multiple epochs, and a crate dependency graph may involve several different epochs simultaneously. Thus, epochs do not split the ecosystem nor do they break existing code.

But it wouldn't hurt to be even more crystal clear and say "there is no such thing as 'requiring' a minimum epoch of client code, only requiring minimum rustc/cargo versions" assuming I am interpreting this right.

@aturon

This comment has been minimized.

Show comment
Hide comment
@aturon

aturon Jul 3, 2017

Member

@cuviper

Will all newly-stabilized features only go into the current epoch? There could be some new things that would be perfectly fine on the older epochs too. My gut says to only push forward, but I could imagine some cases might be harder to try and isolate their implementations.

Ooh, that is a very interesting question that the RFC doesn't address at all. I pretty much agree with both of your sentiments here, and hence suspect we won't have a hard rule, but rather a default tendency. In particular, the benefits of collecting bundles of features together under an umbrella name are decreased somewhat if some of them become available in older epochs.

Is it a semver-breaking change for a crate to start requiring a new epoch? Bumping rustc requirements at all was controversial in #1619.

Another good question. I personally would like to see this issue addressed through LTS releases, which could act as a point of coordination for users wanting to be conservative with their upgrades. I don't think epochs introduce anything particularly new here.

In particular, "requiring" a new epoch means nothing more than requiring a new compiler version, so it reduces to the same question we have today (which we don't have a good answer for yet.)

Will cargo new always default to the newest epoch right away?

Yes. Part of the benefit of keeping the rapid release model at the center here is that we should be able to avoid the usual pitfalls of a "X.0" release.

Member

aturon commented Jul 3, 2017

@cuviper

Will all newly-stabilized features only go into the current epoch? There could be some new things that would be perfectly fine on the older epochs too. My gut says to only push forward, but I could imagine some cases might be harder to try and isolate their implementations.

Ooh, that is a very interesting question that the RFC doesn't address at all. I pretty much agree with both of your sentiments here, and hence suspect we won't have a hard rule, but rather a default tendency. In particular, the benefits of collecting bundles of features together under an umbrella name are decreased somewhat if some of them become available in older epochs.

Is it a semver-breaking change for a crate to start requiring a new epoch? Bumping rustc requirements at all was controversial in #1619.

Another good question. I personally would like to see this issue addressed through LTS releases, which could act as a point of coordination for users wanting to be conservative with their upgrades. I don't think epochs introduce anything particularly new here.

In particular, "requiring" a new epoch means nothing more than requiring a new compiler version, so it reduces to the same question we have today (which we don't have a good answer for yet.)

Will cargo new always default to the newest epoch right away?

Yes. Part of the benefit of keeping the rapid release model at the center here is that we should be able to avoid the usual pitfalls of a "X.0" release.

@cuviper

This comment has been minimized.

Show comment
Hide comment
@cuviper

cuviper Jul 3, 2017

Member

Right, a new epoch requires a new compiler, so yes it's basically the same as bumping rustc generally.

One more - If a 2018+ crate wants to use a 2015 crate with catch in its API, are they just out of luck?

Member

cuviper commented Jul 3, 2017

Right, a new epoch requires a new compiler, so yes it's basically the same as bumping rustc generally.

One more - If a 2018+ crate wants to use a 2015 crate with catch in its API, are they just out of luck?

@est31

This comment has been minimized.

Show comment
Hide comment
@est31

est31 Jul 3, 2017

Contributor

To be clear, there isn't a module system proposal yet

@steveklabnik yes, that's right. The proposals I saw didn't change much in the past few weeks so I'd be suprised if it turned out much different from what was proposed initially on irlo months ago. I don't want to go into the details, as continuing this discussion seems not appropriate for this thread. I only wanted to give motivation for why I like this RFC.

The general point I wanted to make is that I clearly don't want to adapt my code to entirely new concepts/systems every 2 years. Knowing that the proponents of such changes will get them through one way or another, I really do prefer if they were done cleanly (this also helps the feature itself!) and done in newer "epochs" of Rust.

The biggest risk of going with this RFC is I think that it may be misunderstood by people that Rust's stability promise is broken, and making people distrust the promises made by the language, turning them away. To emphasize that epochs are not about breakage but about allowing future evolution, I would really like if it isn't just possible but also accepted and not a sign of bad style to stay with your evolving codebase on an older epoch.

Contributor

est31 commented Jul 3, 2017

To be clear, there isn't a module system proposal yet

@steveklabnik yes, that's right. The proposals I saw didn't change much in the past few weeks so I'd be suprised if it turned out much different from what was proposed initially on irlo months ago. I don't want to go into the details, as continuing this discussion seems not appropriate for this thread. I only wanted to give motivation for why I like this RFC.

The general point I wanted to make is that I clearly don't want to adapt my code to entirely new concepts/systems every 2 years. Knowing that the proponents of such changes will get them through one way or another, I really do prefer if they were done cleanly (this also helps the feature itself!) and done in newer "epochs" of Rust.

The biggest risk of going with this RFC is I think that it may be misunderstood by people that Rust's stability promise is broken, and making people distrust the promises made by the language, turning them away. To emphasize that epochs are not about breakage but about allowing future evolution, I would really like if it isn't just possible but also accepted and not a sign of bad style to stay with your evolving codebase on an older epoch.

@Ixrec

This comment has been minimized.

Show comment
Hide comment
@Ixrec

Ixrec Jul 3, 2017

Contributor

In particular, the benefits of collecting bundles of features together under an umbrella name are decreased somewhat if some of them become available in older epochs.

I suspect the most useful "bundles of features" are ones where some of the features don't come into their own until the rest of the bundle is also stabilized. Like how impl Trait is useful today, but practically mandatory when futures and async/await are involved. Or how CTFE and const fn aren't that useful without each other. So in that sense I don't think stabilizing some "non-breaking" features will weaken a good "bundle".

Contributor

Ixrec commented Jul 3, 2017

In particular, the benefits of collecting bundles of features together under an umbrella name are decreased somewhat if some of them become available in older epochs.

I suspect the most useful "bundles of features" are ones where some of the features don't come into their own until the rest of the bundle is also stabilized. Like how impl Trait is useful today, but practically mandatory when futures and async/await are involved. Or how CTFE and const fn aren't that useful without each other. So in that sense I don't think stabilizing some "non-breaking" features will weaken a good "bundle".

@est31

This comment has been minimized.

Show comment
Hide comment
@est31

est31 Jul 3, 2017

Contributor

One more - If a 2018+ crate wants to use a 2015 crate with catch in its API, are they just out of luck?

I guess there is a limit to the compatibility this RFC can provide?

Contributor

est31 commented Jul 3, 2017

One more - If a 2018+ crate wants to use a 2015 crate with catch in its API, are they just out of luck?

I guess there is a limit to the compatibility this RFC can provide?

@SimonSapin

This comment has been minimized.

Show comment
Hide comment
@SimonSapin

SimonSapin Jul 3, 2017

Contributor

Code that compiles without warnings on the previous epoch (under the latest compiler release) will compile without warnings or errors on the next epoch

As written, I think this excludes ever adding new warnings. You may want to weaken this to "without errors on the next epoch" (but not necessarily without warnings), or "without warnings or errors in the first compiler version that supports the next epoch".

Even then, deprecated stuff cannot be removed or repurposed until two epochs later. This is nice for stability, but maybe a bit heavy for language evolution flexibility. If it is intended, the RFC should mention this.

Contributor

SimonSapin commented Jul 3, 2017

Code that compiles without warnings on the previous epoch (under the latest compiler release) will compile without warnings or errors on the next epoch

As written, I think this excludes ever adding new warnings. You may want to weaken this to "without errors on the next epoch" (but not necessarily without warnings), or "without warnings or errors in the first compiler version that supports the next epoch".

Even then, deprecated stuff cannot be removed or repurposed until two epochs later. This is nice for stability, but maybe a bit heavy for language evolution flexibility. If it is intended, the RFC should mention this.

@aturon

This comment has been minimized.

Show comment
Hide comment
@aturon

aturon Jul 3, 2017

Member

@cuviper

One more - If a 2018+ crate wants to use a 2015 crate with catch in its API, are they just out of luck?

Another good one :-)

There are two ways I can see this going:

  • We can introduce some mechanism for referring to identifiers named as keywords. It might be enough to allow use of keywords within renamed imports, e.g. use foo::catch as catch_;. We'd need to support method renaming, however.

  • Worst case, you can write a shim crate that uses epoch 2015 but re-exports renamed APIs. That can get tricky with traits, though...

Member

aturon commented Jul 3, 2017

@cuviper

One more - If a 2018+ crate wants to use a 2015 crate with catch in its API, are they just out of luck?

Another good one :-)

There are two ways I can see this going:

  • We can introduce some mechanism for referring to identifiers named as keywords. It might be enough to allow use of keywords within renamed imports, e.g. use foo::catch as catch_;. We'd need to support method renaming, however.

  • Worst case, you can write a shim crate that uses epoch 2015 but re-exports renamed APIs. That can get tricky with traits, though...

@aturon

This comment has been minimized.

Show comment
Hide comment
@aturon

aturon Jul 3, 2017

Member

@SimonSapin

Code that compiles without warnings on the previous epoch (under the latest compiler release) will compile without warnings or errors on the next epoch

As written, I think this excludes ever adding new warnings. You may want to weaken this to "without errors on the next epoch" (but not necessarily without warnings), or "without warnings or errors in the first compiler version that supports the next epoch".

Good point. It's probably enough to say "without errors"

Even then, deprecated stuff cannot be removed or repurposed until two epochs later. This is nice for stability, but maybe a bit heavy for language evolution flexibility. If it is intended, the RFC should mention this.

I don't quite follow this point. Examples like the catch keyword involve deprecation in one epoch, then immediate removal/replacement in the next. I don't see how that violates the rule above.

Member

aturon commented Jul 3, 2017

@SimonSapin

Code that compiles without warnings on the previous epoch (under the latest compiler release) will compile without warnings or errors on the next epoch

As written, I think this excludes ever adding new warnings. You may want to weaken this to "without errors on the next epoch" (but not necessarily without warnings), or "without warnings or errors in the first compiler version that supports the next epoch".

Good point. It's probably enough to say "without errors"

Even then, deprecated stuff cannot be removed or repurposed until two epochs later. This is nice for stability, but maybe a bit heavy for language evolution flexibility. If it is intended, the RFC should mention this.

I don't quite follow this point. Examples like the catch keyword involve deprecation in one epoch, then immediate removal/replacement in the next. I don't see how that violates the rule above.

@Ixrec

This comment has been minimized.

Show comment
Hide comment
@Ixrec

Ixrec Jul 3, 2017

Contributor

@aturon A third option would be adding #[cfg(epoch >= 2018)], which would allow crate authors affected by such unfortunate corner cases to swap their catch method for do_catch or whatever else is needed to support >=2018 clients while still staying on the old epoch for the most part.

My guess is we don't actually want to do that, as I can easily imagine overuse of it in a sufficiently large dependency graph leading to compatibility nightmares, and potentially encouraging "people can just cfg it" arguments for epoch changes we would otherwise rightly reject as too breaking. But it seems worth mentioning.

Contributor

Ixrec commented Jul 3, 2017

@aturon A third option would be adding #[cfg(epoch >= 2018)], which would allow crate authors affected by such unfortunate corner cases to swap their catch method for do_catch or whatever else is needed to support >=2018 clients while still staying on the old epoch for the most part.

My guess is we don't actually want to do that, as I can easily imagine overuse of it in a sufficiently large dependency graph leading to compatibility nightmares, and potentially encouraging "people can just cfg it" arguments for epoch changes we would otherwise rightly reject as too breaking. But it seems worth mentioning.

@aturon

This comment has been minimized.

Show comment
Hide comment
@aturon

aturon Jul 3, 2017

Member

Update: per discussion with @Manishearth, I've changed the RFC to default to the 2015 epoch when no flag is given to rustc, since that's more consistent with our general stability story. @nikomatsakis seemed to prefer the latest epoch, but I'll let him argue that point.

Member

aturon commented Jul 3, 2017

Update: per discussion with @Manishearth, I've changed the RFC to default to the 2015 epoch when no flag is given to rustc, since that's more consistent with our general stability story. @nikomatsakis seemed to prefer the latest epoch, but I'll let him argue that point.

@Manishearth Manishearth referenced this pull request Jul 3, 2017

Closed

e-poach RFC #20

@cuviper

This comment has been minimized.

Show comment
Hide comment
@cuviper

cuviper Jul 3, 2017

Member

Do macros operate with the epoch in their crate of origin? I guess they must, but there could be some hairy interactions with stuff that's only legal in the epoch that instantiated it. e.g. oldvec![new-expr]

Member

cuviper commented Jul 3, 2017

Do macros operate with the epoch in their crate of origin? I guess they must, but there could be some hairy interactions with stuff that's only legal in the epoch that instantiated it. e.g. oldvec![new-expr]

@aturon

This comment has been minimized.

Show comment
Hide comment
@aturon

aturon Jul 3, 2017

Member

@cuviper

Procedural macros, in particular, are going to be "interesting" since we can stitch together token streams potentially coming from a mixture of sources.

I haven't thought extensively about this, but I think the ideal behavior would involve some kind of "coloring" of token trees with their epoch of origin. That works well for keywords, since we make the distinction at the lexer level and don't otherwise mind if an identifier happens to have the same name as a keyword.

Other concerns, such as changes to type inference, would likely be much harder to provide a "coloring" strategy for.

I suspect the best we can do is: any time we make an epoch-dependent change, the RFC should contain a section laying out the plan for handling (procedural) macros.

Member

aturon commented Jul 3, 2017

@cuviper

Procedural macros, in particular, are going to be "interesting" since we can stitch together token streams potentially coming from a mixture of sources.

I haven't thought extensively about this, but I think the ideal behavior would involve some kind of "coloring" of token trees with their epoch of origin. That works well for keywords, since we make the distinction at the lexer level and don't otherwise mind if an identifier happens to have the same name as a keyword.

Other concerns, such as changes to type inference, would likely be much harder to provide a "coloring" strategy for.

I suspect the best we can do is: any time we make an epoch-dependent change, the RFC should contain a section laying out the plan for handling (procedural) macros.

@SimonSapin

This comment has been minimized.

Show comment
Hide comment
@SimonSapin

SimonSapin Jul 3, 2017

Contributor

Even then, deprecated stuff cannot be removed or repurposed until two epochs later.

I don't quite follow this point. Examples like the catch keyword involve deprecation in one epoch, then immediate removal/replacement in the next. I don't see how that violates the rule above.

Let’s assume that catch didn’t make it for 2018. let catch = 4; was not a warning in epoch 2015, so the bit of RFC text quoted earlier forbids making it a warning in epoch 2018. We’d have to wait for the next one, let’s call it 2020, to deprecate catch as an identifier and then yet another cycle to be able to make it a keyword in 2022.

So I think we want to drop the "code with warning in one epoch emits no warning in the next" rule. (Reduce it to "no hard error in the next".)

Contributor

SimonSapin commented Jul 3, 2017

Even then, deprecated stuff cannot be removed or repurposed until two epochs later.

I don't quite follow this point. Examples like the catch keyword involve deprecation in one epoch, then immediate removal/replacement in the next. I don't see how that violates the rule above.

Let’s assume that catch didn’t make it for 2018. let catch = 4; was not a warning in epoch 2015, so the bit of RFC text quoted earlier forbids making it a warning in epoch 2018. We’d have to wait for the next one, let’s call it 2020, to deprecate catch as an identifier and then yet another cycle to be able to make it a keyword in 2022.

So I think we want to drop the "code with warning in one epoch emits no warning in the next" rule. (Reduce it to "no hard error in the next".)

@aturon

This comment has been minimized.

Show comment
Hide comment
@aturon

aturon Jul 3, 2017

Member

@SimonSapin ah I see, it was based on reading the literal words I wrote, as opposed to what I had in my head :-)

I've pushed a fix.

Member

aturon commented Jul 3, 2017

@SimonSapin ah I see, it was based on reading the literal words I wrote, as opposed to what I had in my head :-)

I've pushed a fix.

@est31

This comment has been minimized.

Show comment
Hide comment
@est31

est31 Jul 3, 2017

Contributor

Just for clarity, this will fully replace the current pattern of first linting and then turning that lint into error by default then into a hard error, which is being done right now (also has a tag) for smaller breaking changes?

Contributor

est31 commented Jul 3, 2017

Just for clarity, this will fully replace the current pattern of first linting and then turning that lint into error by default then into a hard error, which is being done right now (also has a tag) for smaller breaking changes?

@Aaronepower

This comment has been minimized.

Show comment
Hide comment
@Aaronepower

Aaronepower Jul 3, 2017

How will multi epoch transitions work, especially in relation to the example of changing the Trait syntax? If for example someone writes a program for a company in current Rust, the program's code isn't touched much for a couple of years till lets say mid 2020 and the programmer decides they want upgrade the code. If they simply added epoch = "2020" to Cargo.toml couldn't they have a program that works in both 2015 Rust and 2020 Rust that behaves differently?

Similarly how will the rustfix handle transitioning from arbitrary epochs to the latest? Does it essentially run older versions of itself till it's just at the last old epoch and then run the new changes?

Aaronepower commented Jul 3, 2017

How will multi epoch transitions work, especially in relation to the example of changing the Trait syntax? If for example someone writes a program for a company in current Rust, the program's code isn't touched much for a couple of years till lets say mid 2020 and the programmer decides they want upgrade the code. If they simply added epoch = "2020" to Cargo.toml couldn't they have a program that works in both 2015 Rust and 2020 Rust that behaves differently?

Similarly how will the rustfix handle transitioning from arbitrary epochs to the latest? Does it essentially run older versions of itself till it's just at the last old epoch and then run the new changes?

@SimonSapin

This comment has been minimized.

Show comment
Hide comment
@SimonSapin

SimonSapin Jul 3, 2017

Contributor

Presumably rustfix, like rustc, will need to know about all older epochs. It would fix from 2015 to 2020 by going through 2018, at least internally.

Contributor

SimonSapin commented Jul 3, 2017

Presumably rustfix, like rustc, will need to know about all older epochs. It would fix from 2015 to 2020 by going through 2018, at least internally.

@Aaronepower

This comment has been minimized.

Show comment
Hide comment
@Aaronepower

Aaronepower Jul 3, 2017

Also what if there is a case where the no need for an epoch on year there should be one? For example, it was decided to spend the year refining existing features and adding features that have no stability impact? I don't know if that'd ever be possible, but would a "empty" epoch be released or would it be simply skipped?

Aaronepower commented Jul 3, 2017

Also what if there is a case where the no need for an epoch on year there should be one? For example, it was decided to spend the year refining existing features and adding features that have no stability impact? I don't know if that'd ever be possible, but would a "empty" epoch be released or would it be simply skipped?

@SimonSapin

This comment has been minimized.

Show comment
Hide comment
@SimonSapin

SimonSapin Jul 3, 2017

Contributor

I think it would be pushed to the next year, or whenever it becomes useful. This is why the "preview" is 2015-next (with the previous number), not 2018-pre (which would put a deadline at December 2018).

Contributor

SimonSapin commented Jul 3, 2017

I think it would be pushed to the next year, or whenever it becomes useful. This is why the "preview" is 2015-next (with the previous number), not 2018-pre (which would put a deadline at December 2018).

@KiChjang

This comment has been minimized.

Show comment
Hide comment
@KiChjang

KiChjang Jul 4, 2017

Member

A slight tangent to this RFC: if we are not going to follow semver's version breaking changes and instead adopt epochs, should we just simply drop the "1.x" prefixes on rustc's versions?

EDIT: I think as a corollary to that, we should also ditch semver altogether and figure out what rustc's own versioning scheme should be.

Member

KiChjang commented Jul 4, 2017

A slight tangent to this RFC: if we are not going to follow semver's version breaking changes and instead adopt epochs, should we just simply drop the "1.x" prefixes on rustc's versions?

EDIT: I think as a corollary to that, we should also ditch semver altogether and figure out what rustc's own versioning scheme should be.

@Gankro

This comment has been minimized.

Show comment
Hide comment
@Gankro

Gankro Jul 4, 2017

Contributor

Loose Notes:

  • The core proposed machinery is good and I think it should exist.

  • I would like to emphasize that using epochs to break things is a nuclear option (which the text seems to hint at, but isn't totally clear on). I would personally prefer that we proceed with one of the stated policy alternatives -- "no RFC should qualify its acceptance on the creation of a breaking epoch". That is, every RFC must have a non-breaking version, which is the primary proposal. Breaking things should come only if there's public outcry for it. No point in breaking things for a feature our users don't end up caring much about.

  • I flat-out don't believe the claim that random pieces of code on the internet will start mentioning epochs. Notably, it's impossible to predict when I write something if epochs will be relevant to any particular claim. We also can't expect developers to be aware of things that changed before they ever started using Rust. Something that seemingly "always" has been true might have changed in a much earlier epoch. Also there's just lots of relatively low effort content that ends up living forever like Stack Overflow answers. The fact that epochs will always lead to a Rust-1.0 style documentation confusion is why I consider them to be nuclear.

  • I don't like the "regular" epochs that the RFC seems to be suggesting; I would prefer if they were reserved for "ok we actually broke something". I don't want to have muddy epochs where some of them are totally fine and some actually matter. Although epochs are "beyond" SemVer I would like to keep the spirit of it; it should be easy to tell how hard it is to upgrade.

  • I don't understand why we're calling the alpha releases for 2018 to be "2015-next" -- seems incredibly confusing, considering under this proposal we always know what the final release will be called?

  • The difference between rustc and cargo's epoch defaults seems to be suggesting that only Cargo provides support for reproducible builds? This doesn't make sense to me, can you elaborate?

  • I still think epochs should still be called Sonic Generations, after Rust's official mascot.
    rust-mascot-final

Contributor

Gankro commented Jul 4, 2017

Loose Notes:

  • The core proposed machinery is good and I think it should exist.

  • I would like to emphasize that using epochs to break things is a nuclear option (which the text seems to hint at, but isn't totally clear on). I would personally prefer that we proceed with one of the stated policy alternatives -- "no RFC should qualify its acceptance on the creation of a breaking epoch". That is, every RFC must have a non-breaking version, which is the primary proposal. Breaking things should come only if there's public outcry for it. No point in breaking things for a feature our users don't end up caring much about.

  • I flat-out don't believe the claim that random pieces of code on the internet will start mentioning epochs. Notably, it's impossible to predict when I write something if epochs will be relevant to any particular claim. We also can't expect developers to be aware of things that changed before they ever started using Rust. Something that seemingly "always" has been true might have changed in a much earlier epoch. Also there's just lots of relatively low effort content that ends up living forever like Stack Overflow answers. The fact that epochs will always lead to a Rust-1.0 style documentation confusion is why I consider them to be nuclear.

  • I don't like the "regular" epochs that the RFC seems to be suggesting; I would prefer if they were reserved for "ok we actually broke something". I don't want to have muddy epochs where some of them are totally fine and some actually matter. Although epochs are "beyond" SemVer I would like to keep the spirit of it; it should be easy to tell how hard it is to upgrade.

  • I don't understand why we're calling the alpha releases for 2018 to be "2015-next" -- seems incredibly confusing, considering under this proposal we always know what the final release will be called?

  • The difference between rustc and cargo's epoch defaults seems to be suggesting that only Cargo provides support for reproducible builds? This doesn't make sense to me, can you elaborate?

  • I still think epochs should still be called Sonic Generations, after Rust's official mascot.
    rust-mascot-final

@golddranks

This comment has been minimized.

Show comment
Hide comment
@golddranks

golddranks Jul 4, 2017

@kichang there is value in versioning the compiler separately from the language. One could say that the "1." part of the version number becomes futile if there's never going to be 2.0, but it still essentially communicates the intent, as it's a semver-based version number: "this compiler is still 1.x, and therefore still compatible with the good old Rust!"

golddranks commented Jul 4, 2017

@kichang there is value in versioning the compiler separately from the language. One could say that the "1." part of the version number becomes futile if there's never going to be 2.0, but it still essentially communicates the intent, as it's a semver-based version number: "this compiler is still 1.x, and therefore still compatible with the good old Rust!"

@stepancheg

This comment has been minimized.

Show comment
Hide comment
@stepancheg

stepancheg Jul 4, 2017

Do we need another concept — year-epoch? Could't simply every release of rust introduce a new epoch? And "epoch" would be simply a version of compiler, e. g.

rust_version = "1.20"

BTW, this will also fix an issue of library compatibility with older rust versions. E. g. if Vec adds function like shuffle in 1.21, program should not compile in compiler version 1.21 if epoch is 1.20. This will guarantee that code is compileable with rust 1.20 (and also compilation shouldn't even start with rust 1.19). Epoch mechanism doesn't solve this issue.

stepancheg commented Jul 4, 2017

Do we need another concept — year-epoch? Could't simply every release of rust introduce a new epoch? And "epoch" would be simply a version of compiler, e. g.

rust_version = "1.20"

BTW, this will also fix an issue of library compatibility with older rust versions. E. g. if Vec adds function like shuffle in 1.21, program should not compile in compiler version 1.21 if epoch is 1.20. This will guarantee that code is compileable with rust 1.20 (and also compilation shouldn't even start with rust 1.19). Epoch mechanism doesn't solve this issue.

@SimonSapin

This comment has been minimized.

Show comment
Hide comment
@SimonSapin

SimonSapin Jul 4, 2017

Contributor

A slight tangent to this RFC: if we are not going to follow semver's version breaking changes and instead adopt epochs, should we just simply drop the "1.x" prefixes on rustc's versions?

Staying at 1.x.y forever is a valid use of SemVer. Also I think it helps signal to the outside world that we’re committed to stability.

I’ve said it when 1.0.0 came out and and I still think it: I’m looking forward to the release of Rust 1.100.0 as a proof that our stability story has worked.

Contributor

SimonSapin commented Jul 4, 2017

A slight tangent to this RFC: if we are not going to follow semver's version breaking changes and instead adopt epochs, should we just simply drop the "1.x" prefixes on rustc's versions?

Staying at 1.x.y forever is a valid use of SemVer. Also I think it helps signal to the outside world that we’re committed to stability.

I’ve said it when 1.0.0 came out and and I still think it: I’m looking forward to the release of Rust 1.100.0 as a proof that our stability story has worked.

@Aaronepower

This comment has been minimized.

Show comment
Hide comment
@Aaronepower

Aaronepower Jul 4, 2017

@Gankro

I don't like the "regular" epochs that the RFC seems to be suggesting; I would prefer if they were reserved for "ok we actually broke something". I don't want to have muddy epochs where some of them are totally fine and some actually matter. Although epochs are "beyond" SemVer I would like to keep the spirit of it; it should be easy to tell how hard it is to upgrade.

If the epochs are only released with a breaking change, what makes this different from having a Rust 2.0, other than the name?

Aaronepower commented Jul 4, 2017

@Gankro

I don't like the "regular" epochs that the RFC seems to be suggesting; I would prefer if they were reserved for "ok we actually broke something". I don't want to have muddy epochs where some of them are totally fine and some actually matter. Although epochs are "beyond" SemVer I would like to keep the spirit of it; it should be easy to tell how hard it is to upgrade.

If the epochs are only released with a breaking change, what makes this different from having a Rust 2.0, other than the name?

@carols10cents

This comment has been minimized.

Show comment
Hide comment
@carols10cents

carols10cents Jul 4, 2017

Member

If the epochs are only released with a breaking change, what makes this different from having a Rust 2.0, other than the name?

This is a confusion I had when first introduced to this idea as well. The difference is that code written in, say, epoch 2015 Rust will always compile with every later Rust compiler, such as a hypothetical Rust 1.29 that will support epoch 2018 Rust. See the table in this section of the RFC-- if we were actually making a 2.0 Rust compiler, some of the cells in "Status of catch in epoch 2015" would say "compiler error" instead.

Please keep asking questions on this point if this still isn't clear, we very much want the difference between epochs and semver 2.0 to be clear before coming anywhere close to accepting it. ❤️

Member

carols10cents commented Jul 4, 2017

If the epochs are only released with a breaking change, what makes this different from having a Rust 2.0, other than the name?

This is a confusion I had when first introduced to this idea as well. The difference is that code written in, say, epoch 2015 Rust will always compile with every later Rust compiler, such as a hypothetical Rust 1.29 that will support epoch 2018 Rust. See the table in this section of the RFC-- if we were actually making a 2.0 Rust compiler, some of the cells in "Status of catch in epoch 2015" would say "compiler error" instead.

Please keep asking questions on this point if this still isn't clear, we very much want the difference between epochs and semver 2.0 to be clear before coming anywhere close to accepting it. ❤️

@ubsan

This comment has been minimized.

Show comment
Hide comment
@ubsan

ubsan Aug 31, 2017

Contributor

@aturon That's a good point; I'd still like to minimize churn in this way, and having lots of time to update code for a new epoch definitely does that.

Contributor

ubsan commented Aug 31, 2017

@aturon That's a good point; I'd still like to minimize churn in this way, and having lots of time to update code for a new epoch definitely does that.

@SimonSapin

This comment has been minimized.

Show comment
Hide comment
@SimonSapin

SimonSapin Sep 1, 2017

Contributor

Hard constraints

TL;DR: Warning-free code on epoch N should compile on epoch N+1 and have the
same behavior.

@aturon I don’t we don’t formally do this, but this happens to use (IETF) RFC 2119 terms. The “Hard constraints” section title suggests this should be a must rather than should.

Contributor

SimonSapin commented Sep 1, 2017

Hard constraints

TL;DR: Warning-free code on epoch N should compile on epoch N+1 and have the
same behavior.

@aturon I don’t we don’t formally do this, but this happens to use (IETF) RFC 2119 terms. The “Hard constraints” section title suggests this should be a must rather than should.

@SimonSapin

This comment has been minimized.

Show comment
Hide comment
@SimonSapin

SimonSapin Sep 1, 2017

Contributor

Wording nit-picking aside this looks much better, thanks @aturon !

Contributor

SimonSapin commented Sep 1, 2017

Wording nit-picking aside this looks much better, thanks @aturon !

@emk

This comment has been minimized.

Show comment
Hide comment
@emk

emk Sep 1, 2017

@aturon Thank you for the CC!

These new policy changes address the major concerns that I raised on the module and dyn RFCs.

  • Very low risk of needing to fork unmaintained "dependencies of dependencies" because of an edge case.
  • A good story for Stack Overflow and old documentation. By preferring warnings and "softer" styles of deprecation when possible, this should allow the compiler to educate developers about what has changed.
  • A realistic standard for rustfix. It is neither possible nor desirable for rustfix to handle every imaginable corner case. The last 0.1% of anything can be ruinously expensive. So it's better to analyze these issues at the design stage and use crater-like tools to get empirical data, and to design new language features around the actual ecosystem. This assumes that crates.io is a reasonable proxy for private Rust code.
  • Enough flexibility to allow truly critical changes. For example, if there's ever a Rust equivalent of C's gets, there should be a path to remove it. Similarly, one of the great miseries of C++ has always subtle corner-case interactions between old features and major new features. I could easily imagine a case where a feature like -> impl Trait or await! might require a subtle tweak elsewhere in the language that affects very little code but that has a huge payoff in orthogonality. This latest proposed language provides a good framework for thinking about this.
  • A bias against "medium-payoff" improvements that break a lot of code. Rust developers who aren't on r/rust or Discourse shouldn't need to fear the RFC process as a source of sudden surprises.
  • Cross-crate macros with mixed epochs. I'm kind of amazed that there's a technical solution for this, but it certainly reduces the odds of ugly headaches.

I might have some more thoughts later, but I'm encouraged by the general direction here!

emk commented Sep 1, 2017

@aturon Thank you for the CC!

These new policy changes address the major concerns that I raised on the module and dyn RFCs.

  • Very low risk of needing to fork unmaintained "dependencies of dependencies" because of an edge case.
  • A good story for Stack Overflow and old documentation. By preferring warnings and "softer" styles of deprecation when possible, this should allow the compiler to educate developers about what has changed.
  • A realistic standard for rustfix. It is neither possible nor desirable for rustfix to handle every imaginable corner case. The last 0.1% of anything can be ruinously expensive. So it's better to analyze these issues at the design stage and use crater-like tools to get empirical data, and to design new language features around the actual ecosystem. This assumes that crates.io is a reasonable proxy for private Rust code.
  • Enough flexibility to allow truly critical changes. For example, if there's ever a Rust equivalent of C's gets, there should be a path to remove it. Similarly, one of the great miseries of C++ has always subtle corner-case interactions between old features and major new features. I could easily imagine a case where a feature like -> impl Trait or await! might require a subtle tweak elsewhere in the language that affects very little code but that has a huge payoff in orthogonality. This latest proposed language provides a good framework for thinking about this.
  • A bias against "medium-payoff" improvements that break a lot of code. Rust developers who aren't on r/rust or Discourse shouldn't need to fear the RFC process as a source of sudden surprises.
  • Cross-crate macros with mixed epochs. I'm kind of amazed that there's a technical solution for this, but it certainly reduces the odds of ugly headaches.

I might have some more thoughts later, but I'm encouraged by the general direction here!

@konstin

This comment has been minimized.

Show comment
Hide comment
@konstin

konstin Sep 1, 2017

In addition to the above, compiler error messages should be agnostic to code from old epoch. This means e.g. detecting the usage of newly introduced keywords as identifier.

Another major point is code that is closed source and therefore can't be tested through crater. The rust teams should pair up with the friends of rust companies and gather their feedback before releasing a breaking change. This will avoid unexpected breakage which can be very frustrating otherwise.

konstin commented Sep 1, 2017

In addition to the above, compiler error messages should be agnostic to code from old epoch. This means e.g. detecting the usage of newly introduced keywords as identifier.

Another major point is code that is closed source and therefore can't be tested through crater. The rust teams should pair up with the friends of rust companies and gather their feedback before releasing a breaking change. This will avoid unexpected breakage which can be very frustrating otherwise.

@emk

This comment has been minimized.

Show comment
Hide comment
@emk

emk Sep 4, 2017

Another major point is code that is closed source and therefore can't be tested through crater. The rust teams should pair up with the friends of rust companies and gather their feedback before releasing a breaking change. This will avoid unexpected breakage which can be very frustrating otherwise.

I would imagine that some of the "friends of Rust" companies would be interested in this kind of testing. For my employer, however, here's the reality of how this might work:

  1. Our continuous integration system builds our proprietary code using stable Rust. For various technical reasons, our CI system is unlikely to ever compile any significant fraction of our proprietary code using beta or nightly Rust.
  2. I encourage developers to install nightly Rust and run clippy on all Rust projects. So if something is being actively developed in a given month, it will get tested on nightly Rust. But it's entirely possible for some internal projects to go 6 months or more with no commits. Oddly, this means that if clippy starts working on stable Rust, we'll actually do less testing against nightly Rust!
  3. Even if somebody else volunteered to run a specific rustc branch against our internal code, that would be an administrative nuisance to set up.
  4. If any of our internal projects are using Rust features that aren't also used by a public crate somewhere on crates.io, then that actually worries me, and I'd prefer to fix our code. I learned long ago that as an API user, my only long-term safety is to remain safely "with the herd."

So realistically, while I appreciate the thought of testing proposed Rust features against our internal code, we don't actually have our build system set up in such a way as to make this easy. However, we definitely appreciate crater (or cargo bomb, or whatever it's called), because:

  • It demonstrates that the Rust core team is exceptionally serious about stability. At this level, crater is almost a symbolic thing, a conversational shorthand when speaking to people about Rust: "They actually compile the entirely open source ecosystem when releasing new versions of Rust!" People love hearing this.
  • It means that none of our third-party dependencies are broken by Rust upgrades. And as previously mentioned, I'm actually more concerned about broken dependencies than about needing to fix our own code. Fixing our code is annoying, but at least I have commit bits and won't need to fork anything.
  • crater tests a very large sample of real-world Rust. It doesn't specifically test our code, but it tests a far larger body of code written by many different people.

So that's why I'm willing to accept crates.io as a "proxy" for our internal code. Of course, other companies might feel differently.

emk commented Sep 4, 2017

Another major point is code that is closed source and therefore can't be tested through crater. The rust teams should pair up with the friends of rust companies and gather their feedback before releasing a breaking change. This will avoid unexpected breakage which can be very frustrating otherwise.

I would imagine that some of the "friends of Rust" companies would be interested in this kind of testing. For my employer, however, here's the reality of how this might work:

  1. Our continuous integration system builds our proprietary code using stable Rust. For various technical reasons, our CI system is unlikely to ever compile any significant fraction of our proprietary code using beta or nightly Rust.
  2. I encourage developers to install nightly Rust and run clippy on all Rust projects. So if something is being actively developed in a given month, it will get tested on nightly Rust. But it's entirely possible for some internal projects to go 6 months or more with no commits. Oddly, this means that if clippy starts working on stable Rust, we'll actually do less testing against nightly Rust!
  3. Even if somebody else volunteered to run a specific rustc branch against our internal code, that would be an administrative nuisance to set up.
  4. If any of our internal projects are using Rust features that aren't also used by a public crate somewhere on crates.io, then that actually worries me, and I'd prefer to fix our code. I learned long ago that as an API user, my only long-term safety is to remain safely "with the herd."

So realistically, while I appreciate the thought of testing proposed Rust features against our internal code, we don't actually have our build system set up in such a way as to make this easy. However, we definitely appreciate crater (or cargo bomb, or whatever it's called), because:

  • It demonstrates that the Rust core team is exceptionally serious about stability. At this level, crater is almost a symbolic thing, a conversational shorthand when speaking to people about Rust: "They actually compile the entirely open source ecosystem when releasing new versions of Rust!" People love hearing this.
  • It means that none of our third-party dependencies are broken by Rust upgrades. And as previously mentioned, I'm actually more concerned about broken dependencies than about needing to fix our own code. Fixing our code is annoying, but at least I have commit bits and won't need to fork anything.
  • crater tests a very large sample of real-world Rust. It doesn't specifically test our code, but it tests a far larger body of code written by many different people.

So that's why I'm willing to accept crates.io as a "proxy" for our internal code. Of course, other companies might feel differently.

@aturon

This comment has been minimized.

Show comment
Hide comment
@aturon

aturon Sep 5, 2017

Member

It seems like folks are generally a fan of the revised policy! There may be some more tweaking to do around the pacing of deprecations, but I think we can hash that out with more concrete cases.

I'm still waiting for one more thing before merging, though: whether to stipulate that an epoch cannot change the "meaning" of an existing code phrase that previously compiled. I use quotes here because there are cases under discussion where the old meaning stays intact as a fallback, but a new meaning is layered on top, and we're still trying to sort through the full implications. Once that discussion draws to a close, I'll wrap this RFC up!

Member

aturon commented Sep 5, 2017

It seems like folks are generally a fan of the revised policy! There may be some more tweaking to do around the pacing of deprecations, but I think we can hash that out with more concrete cases.

I'm still waiting for one more thing before merging, though: whether to stipulate that an epoch cannot change the "meaning" of an existing code phrase that previously compiled. I use quotes here because there are cases under discussion where the old meaning stays intact as a fallback, but a new meaning is layered on top, and we're still trying to sort through the full implications. Once that discussion draws to a close, I'll wrap this RFC up!

@joshtriplett

This comment has been minimized.

Show comment
Hide comment
@joshtriplett

joshtriplett Sep 5, 2017

Member

@aturon If we don't say that, then at a minimum, I would stipulate that an epoch cannot make a change unless 1) the previous epoch presented it as an on-by-default lint, and 2) it has a rustfix.

Member

joshtriplett commented Sep 5, 2017

@aturon If we don't say that, then at a minimum, I would stipulate that an epoch cannot make a change unless 1) the previous epoch presented it as an on-by-default lint, and 2) it has a rustfix.

@konstin

This comment has been minimized.

Show comment
Hide comment
@konstin

konstin Sep 5, 2017

Our continuous integration system builds our proprietary code using stable Rust. For various technical reasons, our CI system is unlikely to ever compile any significant fraction of our proprietary code using beta or nightly Rust.

While this might be true for some build systems, there are surely others out there where you can easily start a build with a different rust version or even run a rustfix tooĺ. There are three main reasons why I'd suggest promoting testing on closed source code, beside all the difficulties:

The code bases in enterprise applications tend to be huge compared to open source applications. I don't know about the current situation in rust, but I'd assume that they could significantly increase the number of lines tested. Especially if the code with good integration could be extremely helpfull uncovering otherwise hard to find bugs.

Companies also tend to create weird homegrown workarounds custom solutions in complex systems which are fitted to the needs of a particular company or project and can be found only there. This can be easily observed for enterprise java or c++ code. Having those constructs checked wouldn't be too bad. It would also increase the trust in rust as a platform if developers knew that their software will continue working as expected after the the next release. This might seems like something obvious to someone working with java or python, but having worked in frontend development has unfortunately proven that this wrong. We did for example did have multiple occasions where patch version updates broke our build.

Finally, it should also be highly in the interest of the production users to see how well their code plays with new rust versions and with a future rustfix tool.

konstin commented Sep 5, 2017

Our continuous integration system builds our proprietary code using stable Rust. For various technical reasons, our CI system is unlikely to ever compile any significant fraction of our proprietary code using beta or nightly Rust.

While this might be true for some build systems, there are surely others out there where you can easily start a build with a different rust version or even run a rustfix tooĺ. There are three main reasons why I'd suggest promoting testing on closed source code, beside all the difficulties:

The code bases in enterprise applications tend to be huge compared to open source applications. I don't know about the current situation in rust, but I'd assume that they could significantly increase the number of lines tested. Especially if the code with good integration could be extremely helpfull uncovering otherwise hard to find bugs.

Companies also tend to create weird homegrown workarounds custom solutions in complex systems which are fitted to the needs of a particular company or project and can be found only there. This can be easily observed for enterprise java or c++ code. Having those constructs checked wouldn't be too bad. It would also increase the trust in rust as a platform if developers knew that their software will continue working as expected after the the next release. This might seems like something obvious to someone working with java or python, but having worked in frontend development has unfortunately proven that this wrong. We did for example did have multiple occasions where patch version updates broke our build.

Finally, it should also be highly in the interest of the production users to see how well their code plays with new rust versions and with a future rustfix tool.

@konstin

This comment has been minimized.

Show comment
Hide comment
@konstin

konstin Sep 5, 2017

Btw the rendered link in the original proposal is broken

konstin commented Sep 5, 2017

Btw the rendered link in the original proposal is broken

@scottmcm

This comment has been minimized.

Show comment
Hide comment
@scottmcm

scottmcm Sep 5, 2017

Member

@konstin Fixed; thanks for noticing.

Member

scottmcm commented Sep 5, 2017

@konstin Fixed; thanks for noticing.

@phaylon

This comment has been minimized.

Show comment
Hide comment
@phaylon

phaylon Sep 6, 2017

Personally, I would prefer breaking changes behind feature-flags with fine-grained availability and ways to disable them, and have epochs only act as feature bundles that set the defaults. My reasons are:

  • It would mean I wouldn't ever have to worry about losing features I care about, since I can always re-activate them, or deactivate the things that took it away.
  • It allows me to switch to a new epoch eagerly, and only disable what is currently still in the way of a full upgrade. Then it's easy to refactor piece-by-piece.
  • crates.io can be watched for crates with use-cases requiring adjustments, allowing the features to be refined.
  • A large number of deactivations of a feature in crates without a specific use-case for a reason would point to ergonomics issues with the feature.
  • Having epochs being just points in time where features are defaulted makes them seem more like waypoints in a moving language than a new language version.
  • Constant-availability of features will make it a lot easier to refactor projects to a modern style when they are 10-20 years old, since you can work through changes individually.

phaylon commented Sep 6, 2017

Personally, I would prefer breaking changes behind feature-flags with fine-grained availability and ways to disable them, and have epochs only act as feature bundles that set the defaults. My reasons are:

  • It would mean I wouldn't ever have to worry about losing features I care about, since I can always re-activate them, or deactivate the things that took it away.
  • It allows me to switch to a new epoch eagerly, and only disable what is currently still in the way of a full upgrade. Then it's easy to refactor piece-by-piece.
  • crates.io can be watched for crates with use-cases requiring adjustments, allowing the features to be refined.
  • A large number of deactivations of a feature in crates without a specific use-case for a reason would point to ergonomics issues with the feature.
  • Having epochs being just points in time where features are defaulted makes them seem more like waypoints in a moving language than a new language version.
  • Constant-availability of features will make it a lot easier to refactor projects to a modern style when they are 10-20 years old, since you can work through changes individually.
@ssokolow

This comment has been minimized.

Show comment
Hide comment
@ssokolow

ssokolow Sep 6, 2017

It would mean I wouldn't ever have to worry about losing features I care about, since I can always re-activate them, or deactivate the things that took it away.

The problem is that taking this approach encourages a Perl-like or C++-like situation where the language is really many different personal dialects and it takes a disproportionate effort to gain the kind broad-spectrum competency that employers look for when adding new members to existing projects.

ssokolow commented Sep 6, 2017

It would mean I wouldn't ever have to worry about losing features I care about, since I can always re-activate them, or deactivate the things that took it away.

The problem is that taking this approach encourages a Perl-like or C++-like situation where the language is really many different personal dialects and it takes a disproportionate effort to gain the kind broad-spectrum competency that employers look for when adding new members to existing projects.

@phaylon

This comment has been minimized.

Show comment
Hide comment
@phaylon

phaylon Sep 6, 2017

If the changes are small and few, that shouldn't become a problem, since it'd still be quite close. I'd certainly assume ecosystem usage will vary a lot more and have a lot more impact on peoples experiences.

Additionally, for the full experience you'll need to know the previous epochs as well, since you'll touch multiple epochs over the course of years, and you might want to be able to read code for crates in older epochs.

phaylon commented Sep 6, 2017

If the changes are small and few, that shouldn't become a problem, since it'd still be quite close. I'd certainly assume ecosystem usage will vary a lot more and have a lot more impact on peoples experiences.

Additionally, for the full experience you'll need to know the previous epochs as well, since you'll touch multiple epochs over the course of years, and you might want to be able to read code for crates in older epochs.

@vitiral

This comment has been minimized.

Show comment
Hide comment
@vitiral

vitiral Sep 7, 2017

I love this idea. I particularily like that it will allow the language to continue to evolve over time. However, I think the proposal as-is misses the primary spirit of what I want epochs to be, and I hope others feel the same way

Spirit of Epochs

While epochs certainly give us the ability to roll out new syntax, keywords and even features I think the most important feature is it's ability to remove old cruft. As is the current proposal focuses almost exlusively on our ability to keep piling on features, but the minimalist in me really wants epoch's to primarily be for stripping out old features and unifying APIs/syntax/design patterns.

Even since 1.0, the language is evolving at a fairly rapid pace. It is probable that extern crate will be removed, the mod keyword may even eventually be removed in favor of a filesystem layout (I know this was rejected for now, but it's possible in the future). Lots of other changes are happening that improve ergonomics and readability and would cause code written in 1.0 rust to be practically unreadable to someone who learned "rust 2019".

Epoch's give us the ability to actually remove this old cruft, and I consider that their strongest selling point. We can simplify the language for newbies so that we no longer have to teach things like this. From a learning persepctive, removing things is (almost) always more valuable than adding things.

I would like this spirit to be better expressed in the RFC. At the very least, the first line item under the header "The basic idea" should be added that states:

  • Deprecated APIs and syntax will now generate hard errors, making it easier to teach and read code in the new epoch

vitiral commented Sep 7, 2017

I love this idea. I particularily like that it will allow the language to continue to evolve over time. However, I think the proposal as-is misses the primary spirit of what I want epochs to be, and I hope others feel the same way

Spirit of Epochs

While epochs certainly give us the ability to roll out new syntax, keywords and even features I think the most important feature is it's ability to remove old cruft. As is the current proposal focuses almost exlusively on our ability to keep piling on features, but the minimalist in me really wants epoch's to primarily be for stripping out old features and unifying APIs/syntax/design patterns.

Even since 1.0, the language is evolving at a fairly rapid pace. It is probable that extern crate will be removed, the mod keyword may even eventually be removed in favor of a filesystem layout (I know this was rejected for now, but it's possible in the future). Lots of other changes are happening that improve ergonomics and readability and would cause code written in 1.0 rust to be practically unreadable to someone who learned "rust 2019".

Epoch's give us the ability to actually remove this old cruft, and I consider that their strongest selling point. We can simplify the language for newbies so that we no longer have to teach things like this. From a learning persepctive, removing things is (almost) always more valuable than adding things.

I would like this spirit to be better expressed in the RFC. At the very least, the first line item under the header "The basic idea" should be added that states:

  • Deprecated APIs and syntax will now generate hard errors, making it easier to teach and read code in the new epoch
@ssokolow

This comment has been minimized.

Show comment
Hide comment
@ssokolow

ssokolow Sep 7, 2017

the mod keyword may even eventually be removed in favor of a filesystem layout (I know this was rejected for now, but it's possible in the future)

Hopefully not unless it's replaced by some other keyword which allows the effects of an omitted pub to take effect within the same file. The unfriendliness to non-IDEs is one of the biggest reasons I hate Java's decision to force "err on the side of too many too-tiny files" filesystem layouts based on a metric as simple as "one class per file".

Rust mods can also be ridiculously tiny when their only purpose is to provide visibility isolation for one or more private members.

ssokolow commented Sep 7, 2017

the mod keyword may even eventually be removed in favor of a filesystem layout (I know this was rejected for now, but it's possible in the future)

Hopefully not unless it's replaced by some other keyword which allows the effects of an omitted pub to take effect within the same file. The unfriendliness to non-IDEs is one of the biggest reasons I hate Java's decision to force "err on the side of too many too-tiny files" filesystem layouts based on a metric as simple as "one class per file".

Rust mods can also be ridiculously tiny when their only purpose is to provide visibility isolation for one or more private members.

@SimonSapin

This comment has been minimized.

Show comment
Hide comment
@SimonSapin

SimonSapin Sep 7, 2017

Contributor

Epoch's give us the ability to actually remove this old cruft

No. The compiler still needs to support previous epochs, so stuff can only be disabled, in new epochs, not actually removed. There is no benefit to removing stuff just for the sake of removing.

Deprecated APIs and syntax will now generate hard errors

This suggests that all deprecated things should be systematically removed. I strongly disagree. Breakage should only be considered when it can make way for other benefits, like making catch a keyword to use it in a new language construct.

Contributor

SimonSapin commented Sep 7, 2017

Epoch's give us the ability to actually remove this old cruft

No. The compiler still needs to support previous epochs, so stuff can only be disabled, in new epochs, not actually removed. There is no benefit to removing stuff just for the sake of removing.

Deprecated APIs and syntax will now generate hard errors

This suggests that all deprecated things should be systematically removed. I strongly disagree. Breakage should only be considered when it can make way for other benefits, like making catch a keyword to use it in a new language construct.

@vitiral

This comment has been minimized.

Show comment
Hide comment
@vitiral

vitiral Sep 7, 2017

No. The compiler still needs to support previous epochs ...

Sorry, I should have been more clear: I meant it can be removed from our heads -- which is arguably even more important :)

This suggests that all deprecated things should be systematically removed. I strongly disagree. Breakage should only be considered when it can make way for other benefits, like making catch a keyword to use it in a new language construct.

I didn't say all things should be removed (and I don't think that should necessarily be the case... although I can't really think of a counter-example), but I strongly disagree with your disagreement. Removing things that are deprecated is a benefit in itself, and a very strong one. It makes the langauge more uniform and easier to learn for newbies.

vitiral commented Sep 7, 2017

No. The compiler still needs to support previous epochs ...

Sorry, I should have been more clear: I meant it can be removed from our heads -- which is arguably even more important :)

This suggests that all deprecated things should be systematically removed. I strongly disagree. Breakage should only be considered when it can make way for other benefits, like making catch a keyword to use it in a new language construct.

I didn't say all things should be removed (and I don't think that should necessarily be the case... although I can't really think of a counter-example), but I strongly disagree with your disagreement. Removing things that are deprecated is a benefit in itself, and a very strong one. It makes the langauge more uniform and easier to learn for newbies.

@vitiral

This comment has been minimized.

Show comment
Hide comment
@vitiral

vitiral Sep 7, 2017

@ssokolow I don't want to get into bikeshedding about removing mod -- I meant it only as an example.

vitiral commented Sep 7, 2017

@ssokolow I don't want to get into bikeshedding about removing mod -- I meant it only as an example.

@ssokolow

This comment has been minimized.

Show comment
Hide comment
@ssokolow

ssokolow Sep 7, 2017

@vitiral Likewise. I just wanted the point raised somewhere since I was unaware the discussion you mentioned even happened and it's possible I might miss it if it comes around again.

ssokolow commented Sep 7, 2017

@vitiral Likewise. I just wanted the point raised somewhere since I was unaware the discussion you mentioned even happened and it's possible I might miss it if it comes around again.

@aturon aturon referenced this pull request Sep 14, 2017

Open

Tracking issue for RFC 2052: Epochs #44581

1 of 3 tasks complete
@aturon

This comment has been minimized.

Show comment
Hide comment
@aturon

aturon Sep 14, 2017

Member

After a truly epic (epoch?) -- and remarkably civil and deep -- discussion, this RFC has been merged!

It's likely that we'll want to tweak aspects of the policy for changes outlined in this RFC over time (as some of the recent comments reflect), but this RFC gives a reasonable starting point that stakeholders have found acceptable.

Thanks, everyone, for helping make this RFC what it is!

Tracking issue.

Member

aturon commented Sep 14, 2017

After a truly epic (epoch?) -- and remarkably civil and deep -- discussion, this RFC has been merged!

It's likely that we'll want to tweak aspects of the policy for changes outlined in this RFC over time (as some of the recent comments reflect), but this RFC gives a reasonable starting point that stakeholders have found acceptable.

Thanks, everyone, for helping make this RFC what it is!

Tracking issue.

@aturon aturon merged commit a50ada1 into rust-lang:master Sep 14, 2017

@sgrif

This comment has been minimized.

Show comment
Hide comment
@sgrif

sgrif Sep 14, 2017

Contributor

screen shot 2017-09-14 at 5 35 07 pm

Documented for posterity :trollface:

Contributor

sgrif commented Sep 14, 2017

screen shot 2017-09-14 at 5 35 07 pm

Documented for posterity :trollface:

@toothbrush7777777

This comment has been minimized.

Show comment
Hide comment
@toothbrush7777777

toothbrush7777777 Oct 3, 2017

@aturon The link to the rendered text of the RFC returns 404 Page Not Found. 😢 It needs to be changed to https://github.com/rust-lang/rfcs/blob/master/text/2052-epochs.md.

toothbrush7777777 commented Oct 3, 2017

@aturon The link to the rendered text of the RFC returns 404 Page Not Found. 😢 It needs to be changed to https://github.com/rust-lang/rfcs/blob/master/text/2052-epochs.md.

@carols10cents

This comment has been minimized.

Show comment
Hide comment
@carols10cents
Member

carols10cents commented Oct 4, 2017

@toothbrush7777777 thanks! Fixed!

@sanmai-NL

This comment has been minimized.

Show comment
Hide comment
@sanmai-NL

sanmai-NL Nov 17, 2017

@carols10cents: Could you also add the tracking issue to the RFC please?

sanmai-NL commented Nov 17, 2017

@carols10cents: Could you also add the tracking issue to the RFC please?

@carols10cents

This comment has been minimized.

Show comment
Hide comment
@carols10cents
Member

carols10cents commented Nov 17, 2017

@sanmai-NL done!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment