-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Conversation
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. |
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! ❣️ |
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! |
To be clear, there isn't a module system proposal yet 😉 |
(amusingly, I was just complaining about the lack of this exact feature and philosophy in the OPLSS chat) |
Be careful what things you put in the same sentence, it could sound like a promise ;) |
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 |
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. |
Evidence of @cmr lamenting this missing feature. |
@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. |
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. |
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 |
@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. |
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 |
I guess there is a limit to the compatibility this RFC can provide? |
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. |
text/0000-epochs.md
Outdated
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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW, this can also happen with GCC when they update the default -std
option.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, the drafts I saw here said "default to the 2015 epoch"; we should fix this, IMO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Another good one :-) There are two ways I can see this going:
|
Good point. It's probably enough to say "without errors"
I don't quite follow this point. Examples like the |
@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. |
Update: per discussion with @Manishearth, I've changed the RFC to default to the 2015 epoch when no flag is given to |
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. |
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. |
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".) |
@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. |
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? |
How will multi epoch transitions work, especially in relation to the example of changing the Similarly how will the |
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:
|
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. |
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. |
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:
|
Hopefully not unless it's replaced by some other keyword which allows the effects of an omitted Rust |
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 |
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. |
@ssokolow I don't want to get into bikeshedding about removing |
@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. |
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 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 thanks! Fixed! |
@carols10cents: Could you also add the tracking issue to the RFC please? |
@sanmai-NL done! |
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 an edition every two or three years. Editions 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 edition 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 edition. Existing code continues to compile, and crates can freely mix dependencies using different editions.
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