What if the transition to Rust 2.0 can be fully machine applicable? (with `cargo fix`)

Rust 2.0 is unlikely to ever happen as it would fragment the ecosystem. But what if there are changes we want that:

  • Are breaking and cannot be made in a version or an edition: Rust 2.0 won't be able to call Rust 1.0 code
  • Can be machine applicable with cargo fix

Could Rust 2.0 happen in this way? Any Rust 1.0 code can be transitioned automatically to Rust 2.0 and will continue to compile and behave the same.

this idea does not include any suggestions for which changes exactly fit the 2 above criteria. But if these changes do exist, and they pile up over the next few decades then potentially Rust 2.0 could actually happen. Thoughts?

Yes, this is a thing that could happen.

1 Like

Python2 was supposed to have automatic conversion to Python3, and it didn't work out for them.

If Rust 2.0 can't call 1.0 code, then you can't upgrade until your dependencies upgrade, and your dependencies won't upgrade, because everyone who uses them is on Rust 1.0.

6 Likes

If Rust 2.0 can't call 1.0 code, then you can't upgrade until your dependencies upgrade, and your dependencies won't upgrade, because everyone who uses them is on Rust 1.0.

I would like to point out that this is already kind of the case with editions. There you totally can call code from an older edition, but you can't update to a newer edition as long as your dependencies are not at least compatible with the newer edition. Known cases of incompatibilities to newer editions include anything dependent on how cargo resolves dependencies/features as this might change between editions. If any of your dependencies made such an assumption that can easily lead to cases where you cannot simply update to a new edition. Now this is more like an edge case with the edition system today, but it's not something that cannot happen.

As for the suggestion of making all changes machine applicable with cargo fix: Given the experience with the past 3 editions and me maintaining diesel I think I can confidently state that this won't happen because it's just not possible with a reasonable amount of effort. My feeling there is that project (reasonably!) won't promise something like this because then they need to handle every edge case.

You can still pick the old resolver with a newer edition. The edition only picks the default resolver, it doesn't force a particular resolver.

That's correct, but I would like to argue that as long as that's not the default behavior and that's not discoverable/suggested by cargo it basically does not exist for users running into this problem.

That's the catch 22:

If you can upgrade with just a cargo fix, it's not a 2.0

5 Likes

Any change that is machine applicable could, in theory, also be implemented as an edition.

Proof: When compiling a crate using an old edition, the compiler can simply do the automatic migration to the newest edition as its first compilation step – similarly to how Deno can run both TypeScript and JavaScript by converting TS to JS on-the-fly.

What's preventing bigger edition changes is this rule:

Rust should feel like “one language”

An edition change that makes Rust feel like a different language will likely not be accepted, even if it is technically possible.

5 Likes

I'd argue that there's a bunch of ways which we could make backwards-incompatible changes that makes the language feel truer to the Rust ideal, but with some code getting broken, including (though maybe smart people can figure out how to make these a normal edition change instead):

  • Leak/Forget auto-trait restricting the ability to leak values without calling the destructor
  • Future trait which is generic on the context being passed in, such that you can get a compile error if you try to run a future dependent on one runtime inside of another, instead of the current approach where you get a runtime panic.
4 Likes

This shouldn't be part of Future, and many many futures do not produce a panic if run on a different runtime. Some futures are completely runtime agnostic. And even among those that aren't, panicking when run without a specific runtime is a tokio-specific problem.

1 Like

Some embassy futures are panicking too by the way

I believe you're missing the point, unfortunately.

The problem with Rust 2 features is not to restore the current behaviour automatically - which often is easy - but to decide when to use it.

Example: Linear types Idea: some types must be destructured explicitly. Types can opt-in to have a drop function doing this, by implementing a Drop trait.

Today, all types would implement the Drop trait, so the auto fix is easy. Generate an implentation of drop trait using the current drop function. For generic parameters, always assume drop.

This will work just fine. But then, the standard library wants to adapt the feature and adjust its API. At this point, the fix-tool needs to make a change, using the new API or the old. This may actually work out in explicit cases, but as soon as you have generics, it breaks down. There need to be manual decision, which will be mostly obvious for the developer, but will break the tool.

2 Likes