2021 edition?

That will require slowing the rate of improvements to rustc. There is a wg-grammar chartered to create a quasi-standard syntax for Rust that is not dependent on rustc. However, standardizing the semantics of things like borrow checking will require that improvements such as Polonius not occur. Otherwise Rust crates that compile on rustc may not compile on a competing standard-conforming compiler.

Personally, given Rust's 6-week release train, I believe that Rust will need a few more years of development / improvement before Rustaceans can afford to slow its progress enough for an IETF standard, let alone an ISO standard.

4 Likes

Not necessarily. You can standardize "Rust 1.42" and still keep improving rustc, rustc just won't implement (just) "Rust 1.42" anymore. It's like how the Sealed Rust project is seeking to strictly formalize a subset of Rust; you can formalize a subset of what rustc actually implements, and call the rest implementation extensions. The difference only really comes up when you get people telling you to program to the specification instead of the compiler (of which there is benefit, I will not argue against.)

I think people overestimate the benefit of a standard and/or misattribute what they want to being the standard (when it's maybe multiple implementations, or maybe just a design specification distinct from the implementation). In either case, this isn't the thread to discuss a spec in.

10 Likes

I disagree with this. While there isn't a standard yet, planning for forward compatibility is always useful. Editions are an excellent way of planning for this, especially if the standard and the editions move together. This is entirely analogous to talking about K&R C (not a standard), or C99, C11, and C18 (all of which are standards). The only difference is that rust got the naming convention correct right from the start (full 4 digit years, so we don't have to worry about namespace collisions for another 10,000 years).

I fully agree with you on this! IMHO, rust hit 1.0 too soon, there are a number of weird things that don't feel very smooth to me (not wrong per se, just not smooth). That said, I agree with that @CAD97 said:

I also agree with:

I was only stating that editions are good ways of marking what you're compatible with, and what you aren't compatible with, and noting that it would very useful whenever rust is fully specified in the future.

I was just looking at this post on users where someone was asking why a Range was moved into the loop, and I thought that this could be solved with editions. We could provide a new set of range types and on the 202x+ edition we desugar range literals to the new types and on 2015/2018 we desugar range literals to the old types.

The new range types would have all public fields, and would implement Copy. They would also implement IntoIterator which would convert them into the old range types or some new custom range iterator.

I don't know if this is worth the churn, but the range types we have right now are a pain to use because they aren't Copy and because RangeToInclusive doesn't expose it's fields. This change wouldn't require any sort of api gating, so it should be relatively simple to implement.

If we want to clean up the api, we can move the old range types to a seperate module and rexport them out of core::ops and eventually remove them from core::ops, but that's a different dicussion.

6 Likes

To back up from the the whole "Rust has no formal spec yet" tangent, although there's obviously no official / de jure answer to this, we can very easily give a simple and clear de facto answer:

Yes, because one of the major goals of editions is to enable crates to interoperate across however many editions we end up creating in the future, and failing to support a large chunk of crates.io crates is clearly a non-starter for any competing Rust implementation.

Although I'd probably phrase it differently since the precise wording you chose arguably implies that it'd also have to be "bugward compatible" with any code that Rust 1.0 compiled but later versions intentionally broke for whatever reason other than edition changes. I think we can safely assume nobody would expect or ask for a competing compiler to attempt that.

1 Like

Oof... I think that would effectively mean that there will only ever be one rust compiler in the wild. Although I guess a non-conforming compiler could explicitly state that it only supports edition 20XX forwards, and give hard errors when it encounters code from earlier...

To be fair, there are very few breaking changes between editions. IIRC most of it is just stuff like "async is a keyword in 2018 but a legal identifier in 2015". Compared to all the other things a competing Rust compiler would have to support, I doubt this comes anywhere near the list of hardest problems to solve.

5 Likes

Supporting multiple editions is specifically constrained to be a low burden for implementors. Only surface syntax is allowed to differ based on the edition flag:

The Rust compiler supports multiple editions, but must only support a single version of "core Rust". We identify "core Rust" as being, roughly, MIR and the core trait system; this specification will be made more precise over time. The implication is that the "edition modes" boil down to keeping around multiple desugarings into this core Rust, which greatly limits the complexity and technical debt involved.

Adding support for an older edition should be both easy and straightforward, especially compared to most of the other work required to implement a Rust compiler.

7 Likes

Thank you for the link to that RFC, I'll read it over when I have time.

OK, so things like async are sugar only, correct? Thus, since they can be lowered to MIR, they 'don't really count' as they can be added easily, correct? I just want to be sure I'm understanding things correctly.

That said, if I understand the statement 'must only support a single version of "core Rust".' correctly, then this is great news! Once core rust has stabilized a little more, the spec can be for that. Editions can just be sugar instead of a full ISO/IEC spec, kind of like how HTML 5 is a 'living spec'.

So, I know I'm hijacking this thread (I'll start another thread if there is enough interest), but has any work been done on making a real spec for core rust? Is that what Sealed Rust and RustBelt heading towards?

The short answer is probably "yes" to all of that, but the only way to "be sure you're understanding things" is to read the RFC on the subject. For example, whether async is "sugar only" kinda depends on exactly what you mean by "async" and "sugar", since it does affect borrow checking and in some sense was bundled with the std::futures machinery and a generators feature that's still unstable. But in general, anything else I could say here would just be copy-pasting text from that RFC.

Feel free to start a new thread if you have additional questions after reading the RFC.

Depends on what "real spec" means. If we're talking a formal ISO specification document like C++, probably not. If we're talking an officially endorsed exhaustive and normative description of Rust semantics, then absolutely yes. The Grammar working group is yet another project tackling a piece of this spec work.

Would adding a Copy bound be a breaking change? Why?

No, it wouldn't, but it is an explicit design decision not to add Copy to iterators directly. You can see this with other iterators like std::iter::Empty and std::iter::Once, even though both of those could be Copy they aren't. This is fine for iterators because they are usually one shots, but ranges have a much broader use than just iterators. So forcing them inline makes them harder to use.

1 Like

I'm completely comfortable with this, as long as it is mathematically unambiguous. Note that UB is actually unambiguous in many cases; I know that if I do certain things, then I know without ambiguity that I'll be getting UB. I just get really annoyed when I can't decide if something is legal rust or not, and when I can't decide what something actually means.

3 Likes

It would cause churn, and async has used up all of Rust's churn budget for the next decade.

What about potential massive drastic refactorings after stabilisation of const generics and GATs?

Rust is currently missing some fundamental pieces needed for good design, so I think more waves of churn is inevitable if Rust is going to evolve.

4 Likes

Both will cause churn in the wild, but the important difference is that removal of deprecated APIs forces code changes before adopting a new edition. Use of cool new features is voluntary, and doesn't have to be done before switching editions.

3 Likes

Are you suggesting that the new range type doesn't implement Iterator directly? That would break a lot of code, since code like (1..n).enumerate() no longer compiles. If you really need the Copy bound, you could create a struct that implements Copy and From<Range>.

@yaahc kindly wrote up some notes from the edition call:

5 Likes

Yes, but only on the new edition. We could have rustfix automatically add into_iter if it detects any of Iterator's methods being used on ranges. So there isn't breakage, but it will require some more work to migrate.

That's true, I just find that to be really inconvenient, especially when the whole point of Range* is convenience.

There is also the problem that RangeToInclusive has private fields, which make it less ergonomic to use than any other range type.

Admittedly, these are not really a huge deal, I just thought they would make the range sugar much easier to use. (As I said in the op, I don't know if this is worth the cost)

4 Likes

OK, so did we decide to go for a 2021 edition or not? I feel like we all just stopped talking, but never came to any conclusions on this.

There wasn't a decision made in this thread. The core team is still discussing it, even if this thread died out.

1 Like