Rust 2018: an early preview

The Rust teams having been working hard to implement features of the 2018 edition. Today we have reached an important milestone: we are announcing that we have an alpha-quality preview of the 2018 edition ready for testing and feedback.

The preview presents a great opportunity for those of you using the stable channel to switch to nightly and try out how it feels to code in the new edition, both to help us fix bugs and to provide feedback – positive and negative – on features. To get nightly, run rustup install nightly. If you’re already on the nightly channel, it’s likely that there’s no need to update the compiler.

As part of this preview, we have produced a first draft of the Edition Guide, which walks through the mechanics of editions, how to migrate your code, and all of the new features planned for Rust 2018.

While some major features intended for Rust 2018 have already stabilized, there are a number of remaining features that we’re particularly eager for feedback on:

Of course, we’re also keen to hear about your experience with newly stabilized features, including impl Trait, dyn Trait, slice patterns, and more.

The current Edition Preview is at alpha quality: it’s quite rough around the edges, but sufficiently feature-complete to get a feel for coding in the new edition. Some code will fail to migrate via rustfix today — in particular, rustfix generally does not work well with macro-generated code. We expect this experience to improve over time.

There are directions for migrating crates to the edition. The guide also contains a list of features currently part of the preview, with links to their tracking issues where you can leave feedback. If you have feedback about the edition in general, please open a thread on internals.rust-lang.org with the category set to Edition 2018 Feedback. A dedicated channel for discussion has been created on IRC (irc.mozilla.org), #rust-edition. Let us know what you think!

Unfortunately, this preview release doesn’t include a few features planned for Rust 2018. Some examples are below:

Expect to see follow-up announcements when these features are ready for alpha testing.

56 Likes

I just want to give my heartfelt thanks to the huge number of people, across all the Rust teams, who’ve helped get us to this place!

And I want to give a special shoutout to @Manishearth, @killercup, @Mark_Simulacrum, @Centril, @steveklabnik, @alexcrichton and @nikomatsakis, who collectively did the work of getting the preview itself ready to go.

Go team! :tada::heart:

29 Likes

Yay! and thank y’all!

We have the best teams. :crab:

2 Likes

Hooray!

Quick note: the link to slice patterns is broken, it should be: https://rust-lang-nursery.github.io/edition-guide/2018/transitioning/slice-patterns.html

3 Likes

Fixed, thanks!

Is the Edition Guide working? I only see an intro page that says to read on, but there don’t appear to be any other content.

There should be a sidebar with a table of contents

If you’re on mobile, it might be less obvious; click the upper left corner, there should be an icon. If not, click anyway :slight_smile:

Apparently there’s an mdbook bug, this should be fixed very soon.

1 Like

I’m really excited for the new module system! :slight_smile:

3 Likes

Not sure where this should be reported, but I think there’s a typo near the top of https://rust-lang-nursery.github.io/edition-guide/2018/transitioning/ownership-and-lifetimes/lifetime-elision-in-impl.html where impl<'a, 'b> SomeTrait<'a> for SomeType<'a, 'b> is contrasted with impl SomeTrait<'tcx, 'gcx> for SomeType<'tcx, 'gcx>. Somehow SomeTrait<...> went from one lifetime parameter to two lifetime parameters. That is a typo, right?

In the guide, I think the Feature Status page is missing a separation between:

  • Features that actually require the edition = "2018" opt-in in Cargo.toml, for example because they involve a breaking change such a keyword that was previously a valid identifier
  • Other features, which are “only” considered part of Rust 2018 because they affect idioms and are somewhat recent, but are in fact available to 2015-edition-crates, assuming a recent enough compiler.

you no longer need to write extern crate to import a crate into your project.

[…]

Now, to add a new crate to your project, you can add it to your Cargo.toml, and then there is no step two. If you're not using Cargo, you already had to pass --extern flags to give rustc the location of external crates, so you'd just keep doing what you were doing there as well.

If I remember correctly, --extern is not used for crates that are in the sysroot. Is for example extern crate proc_macro; also not needed anymore, and use proc_macro::TokenStream; sufficient for that crate to be linked?

In Rust 2018, you'd write:

fn two_args(foo: &Foo, bar: &'bar Bar) -> &'bar Baz

In other words, you can drop the explicit lifetime parameter declaration, and instead simply start using a new lifetime name to connect lifetimes together.

The example suggests that the lifetime is named after the value-parameter, but the prose suggests it is not. Which is it? In other words, is this valid?

fn two_args(foo: &Foo, bar: &'somethingelse Bar) -> &'somethingelse Baz

Similarly in the “Lifetime elision in impl” page:

    // we can refer to 'arg, rather than conflicting with 'a
    fn bar(&self, arg: &str) -> &'arg str
3 Likes

Is async still planned for Rust 2018? (It’s listed in the Edition Guide table of contents and Feature Status page, so I’m assuming so.) If so, I think it should be listed among the features not included of the preview release, right?

The list in the post above isn’t exhaustive – I’ve added a note about that. However, I believe that we don’t expect async/await to land in time for the initial 2018 edition release, though it should land shortly thereafter. There isn’t an implementation yet in nightly even so it’s somewhat unknown what the exact timeline will be.

It pains me to say, but like many still casually watching / not directly participating, I too feel like things are continuing to churn in the language a bit … beyond reason. Impl Trait, SIMD and slice patterns seem worthwhile (the latter two have been on the books forever). The other bits … I dunno, seem like many are cases of “it worked before”.

I know (and very much respect) that you’re making strong promises in terms of forever-supporting older editions, and “nobody has to use the new stuff”, but I still think there’s value to the great majority of people who will see code out of context without tracking editions in their heads, to keeping the inter-edition delta as small as possible, slowing velocity to changes that are really necessary, keeping the language as close to a single dialect as possible.

I’m not saying this to preserve some special shiny parts of the language I made / liked; much of that was either gone or set in stone by 1.0 anyways. I’m saying it because I want to preserve the exceptionally rare and beautiful success the Rust-you-all-built for 1.0 has experienced so far, and I think it’s hard to see clearly when your day job and/or passionate hobby is hacking on the compiler just how much unnecessary churn does pose a risk to its future. There’s already a ton in the language, and a ton for people to learn / train-on / document / get used to, and a ton of quality work to do on the implementation, integrations and libraries even if no more language features are ever added. Every unnecessary change puts strain on that.

42 Likes

I've read through most of the 2018 features, and one thing I found lacking, which is essential for trying them out, is how to "enable" them and how to "lint" for opportunities to apply them. (For some there is information on how to enable, but for most there isn't.)

For example one of my favorite additions, the dyn Trait one is enabled by default, but you have to also #[warn(bare_trait_objects)] in order to get pointed to where it should be applied.


Regarding the module system changes, I have two "minor issues" with the path clarity feature, namely:

  • I found it to be extremely useful to always use extern cate something, as it provides a nice overview from the source code of what libraries are used;
  • using just crate struct Something (instead of pub(crate) struct Something) has two drawbacks:
    • for once it overloads the "semantic" of the keyword crate; (you can use it (although optionally) in extern crate something, as a "root" for module paths as in use crate::something, then as a visibility modifier crate struct Something, and I'm sure there are other options I don't know of;)
    • having only pub and pub(<something>) as the only visibility specifier made things easier to search for (for example via regular expressions), and it was also more "intuitive" for people not accustomed with all of Rust's "specificities";

Regarding the new ownership and lifetimes features:

  • the anonymous lifetime -- I tried to enable #[warn(elided_lifetimes_in_paths)] to see where it might be applied and I think it'll take me an entire day to correct my code... moreover I don't see exactly what advantages does it bring? (I mean if a function returns a structure which contains borrowed values, then the compiler will complain, thus it will be even more clearer than looking into the definition of that function; moreover it will make refactoring code even more involved when one introduces a new lifetime in an internal structure;)
  • in-band lifetimes and lifetime elision in impl -- I love these feature as it will make my life easier (and my signatures more sane);
  • default match bindings -- i.e. no more random sequences of &, ref and * in my match statements -- love this!

Just wanted to say I also love these three additions, especially the impl Trait which makes it even more easier to create generic functions (and thus hopefully improve performance).

For example I had a lot of functions like pub fn some_functionality <FirstValueRef : AsRef<Value>, SecondValueRef<AsRef<Value>> (first : &FirstValueRef, second : &SecondValueRef) { ... } which I now can write as simple as pub some_functionality (first : &impl AsRef<Value>, second : &impl AsRef<Value>) {...}. Moreover I also have some functions that use plain &Value as arguments, which I can now transform into generics by just "find-and-replace" &Value with &impl AsRef<Value>.

Moreover the addition of &dyn Trait allows me to visually find places in my code where I could use &impl Trait in order to convert them to generics.


All in all great work on getting Rust more "production friendly"!

I welcome any change that reduces the random "character soup" (which as said involves &, *, ref and similar) especially in match statements and working with simple wrappers such as Option<&T> or references.

4 Likes

While the macro imports for module system change is a nice improvement, I would prefer keeping the bang in the import to show that this is not a function.

use bar::baz!;
25 Likes

Hasn’t Swift, which you now work on IIRC, chosen the same path of making refinements even if it means breaking compatibility, though?

And Swift has even more compatibility/stability pressure, given that it’s promoted as “the” way to write iOS software, that is, affecting a multi $100 billion dollar market.

The pace of change and the “swift enhancement proposals” I see (which I understand, you’re not of course influencing yourself completely, its a larger team) seem to go at a much faster pace (and even even more trivial ergonomic or sugary changes).

As someone who spends a lot of time writing C++ code, I would like to point out that raw language power/expressivity (which is what your post seems to focus on) is not everything. Polish and usability matter too, and some of that work must be done at the language level.

That being said, I can certainly understand that one person’s polish is another person’s unnecessary fluff/churn :slight_smile:

11 Likes

With all that trend to simplifications, please don’t convert Rust to Ruby. Rust is more precious, when we talk about programming languages. I love explicit syntax of Rust, wholeheartedly.

6 Likes

I think I’ve found a small syntax inconsistency in the code samples of the Edition Guide concerning in-band lifetimes. Filed an issue for that.

This detail aside, after reading through the guide, I’d say it does a good job of introducing the currently enumerated features, concisely but precisely enough. In particular, I deeply appreciate to have a short reference text on the new modules/path and lifetime situations: I got drowned in all the RFC discussions and was unable to get a clear picture of where this was all going so far.

One scope question though. One of the proposed roles of editions is that “For active Rust users, it brings together incremental changes into an easy-to-understand package”. If so, shouldn’t this Edition guide also mention present some major features which were landed between Rust 2015 and Rust 2018, such as the ? early exit syntax or custom derives?

2 Likes