Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.
Sign upRFC: Evolving Rust through Epochs #2052
Conversation
aturon
added
the
T-core
label
Jul 3, 2017
aturon
self-assigned this
Jul 3, 2017
This comment has been minimized.
This comment has been minimized.
|
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. |
This comment has been minimized.
This comment has been minimized.
|
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 |
This comment has been minimized.
This comment has been minimized.
|
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! |
This comment has been minimized.
This comment has been minimized.
To be clear, there isn't a module system proposal yet |
This comment has been minimized.
This comment has been minimized.
|
(amusingly, I was just complaining about the lack of this exact feature and philosophy in the OPLSS chat) |
This comment has been minimized.
This comment has been minimized.
Be careful what things you put in the same sentence, it could sound like a promise ;) |
This comment has been minimized.
This comment has been minimized.
|
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 |
This comment has been minimized.
This comment has been minimized.
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. |
This comment has been minimized.
This comment has been minimized.
|
Evidence of @cmr lamenting this missing feature. |
This comment has been minimized.
This comment has been minimized.
|
@cuviper The cargo question is answered explicitly in the RFC:
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:
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. |
This comment has been minimized.
This comment has been minimized.
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.
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.)
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. |
This comment has been minimized.
This comment has been minimized.
|
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 |
This comment has been minimized.
This comment has been minimized.
@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. |
This comment has been minimized.
This comment has been minimized.
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 |
This comment has been minimized.
This comment has been minimized.
I guess there is a limit to the compatibility this RFC can provide? |
This comment has been minimized.
This comment has been minimized.
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. |
Manishearth
reviewed
Jul 3, 2017
| We'll wrap up with the full details of the mechanisms at play. | ||
|
|
||
| - `rustc` will take a new flag, `--epoch`, which can specify the epoch to | ||
| use. This flag will default to the current epoch. |
This comment has been minimized.
This comment has been minimized.
Manishearth
Jul 3, 2017
Member
This is interesting.
I prima facie agree with this choice. It makes sense for the CLI tool to default to the latest epoch for ease of use.
But this does bring into question the stability of said CLI tool. We have thus far treated rustc as a tool with stable flags and behavior; with the stable release not having any unstable flags (etc).
However, this does mean that rustc foo.rs may stop compiling if you upgrade your compiler (for reasons other than soundness bugfixes yada yada), which is not "stable" as I understand the current definition of stability for the rustc CLI tool.
We can, of course, choose to change this definition (or I may simply be wrong as to how we evaluate stability for rustc) but I do think that this is a subtlety that should be highlighted and perhaps discussed more. So far we largely assume that most consumers of rustc are using it through cargo, but we are likely to have more and more direct consumers as it gets integrated with alternate build systems (like Bazel). We can make it the responsibility of these build systems to explicitly set the epoch, but again, this is technically a breaking change.
This comment has been minimized.
This comment has been minimized.
aturon
Jul 3, 2017
Member
Yeah, I figured that people with stability concerns here would just always pin an epoch in their arguments. However, I think this is a small detail that could easily go either way.
This comment has been minimized.
This comment has been minimized.
cuviper
Jul 3, 2017
Member
FWIW, this can also happen with GCC when they update the default -std option.
This comment has been minimized.
This comment has been minimized.
steveklabnik
Jul 3, 2017
Member
Yes, the drafts I saw here said "default to the 2015 epoch"; we should fix this, IMO.
This comment has been minimized.
This comment has been minimized.
SimonSapin
Jul 3, 2017
Contributor
I read through the entire RFC but missed this detail. I saw that Cargo defaults to epoch = "2015" and assumed that rustc would too.
I think this should be reconsidered. Rust-aware build systems other than Cargo can also decide to enable the latest epoch as part of their template for new projects.
This comment has been minimized.
This comment has been minimized.
Another good one :-) There are two ways I can see this going:
|
This comment has been minimized.
This comment has been minimized.
Good point. It's probably enough to say "without errors"
I don't quite follow this point. Examples like the |
This comment has been minimized.
This comment has been minimized.
|
@aturon A third option would be adding 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. |
This comment has been minimized.
This comment has been minimized.
|
Update: per discussion with @Manishearth, I've changed the RFC to default to the 2015 epoch when no flag is given to |
This comment has been minimized.
This comment has been minimized.
|
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. |
This comment has been minimized.
This comment has been minimized.
|
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. |
This comment has been minimized.
This comment has been minimized.
Let’s assume that 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".) |
This comment has been minimized.
This comment has been minimized.
|
@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. |
This comment has been minimized.
This comment has been minimized.
|
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? |
This comment has been minimized.
This comment has been minimized.
Aaronepower
commented
Jul 3, 2017
|
How will multi epoch transitions work, especially in relation to the example of changing the Similarly how will the |
This comment has been minimized.
This comment has been minimized.
|
@konstin Fixed; thanks for noticing. |
This comment has been minimized.
This comment has been minimized.
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:
|
This comment has been minimized.
This comment has been minimized.
ssokolow
commented
Sep 6, 2017
•
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. |
This comment has been minimized.
This comment has been minimized.
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. |
This comment has been minimized.
This comment has been minimized.
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 EpochsWhile 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 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:
|
This comment has been minimized.
This comment has been minimized.
ssokolow
commented
Sep 7, 2017
Hopefully not unless it's replaced by some other keyword which allows the effects of an omitted Rust |
This comment has been minimized.
This comment has been minimized.
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.
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 |
This comment has been minimized.
This comment has been minimized.
vitiral
commented
Sep 7, 2017
Sorry, I should have been more clear: I meant it can be removed from our heads -- which is arguably even more important :)
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. |
This comment has been minimized.
This comment has been minimized.
vitiral
commented
Sep 7, 2017
|
@ssokolow I don't want to get into bikeshedding about removing |
This comment has been minimized.
This comment has been minimized.
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. |
This comment has been minimized.
This comment has been minimized.
|
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! |
aturon
merged commit a50ada1
into
rust-lang:master
Sep 14, 2017
This comment has been minimized.
This comment has been minimized.
mgattozzi
referenced this pull request
Sep 26, 2017
Closed
Should work continue on current rustdoc? #176
This comment has been minimized.
This comment has been minimized.
toothbrush7777777
commented
Oct 3, 2017
•
|
@aturon The link to the rendered text of the RFC returns 404 Page Not Found. |
This comment has been minimized.
This comment has been minimized.
|
@toothbrush7777777 thanks! Fixed! |
scottmcm
referenced this pull request
Oct 7, 2017
Merged
Add "Update rendered link" to RFC merge procedure #105
This comment has been minimized.
This comment has been minimized.
sanmai-NL
commented
Nov 17, 2017
|
@carols10cents: Could you also add the tracking issue to the RFC please? |
This comment has been minimized.
This comment has been minimized.
|
@sanmai-NL done! |


aturon commentedJul 3, 2017
•
edited by carols10cents
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:
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