diff --git a/src/rust-2018/path-clarity.md b/src/rust-2018/path-clarity.md index aa0eee26..cfe18f83 100644 --- a/src/rust-2018/path-clarity.md +++ b/src/rust-2018/path-clarity.md @@ -12,11 +12,24 @@ As such, the 2018 edition of Rust introduces a few new module system features, but they end up *simplifying* the module system, to make it more clear as to what is going on. +Note: During the 2018 edition preview, there are two variants of the module +system under consideration, the "uniform paths" variant and the "anchored use +paths" variant. Most of these changes apply to both variants; the two variant +sections call out the differences between the two. We encourage testing of the +new "uniform paths" variant introduced in edition preview 2. The release of +Rust 2018 will stabilize one of these two variants and drop the other. + Here's a brief summary: * `extern crate` is no longer needed -* Absolute paths begin with a crate name, where the keyword `crate` - refers to the current crate. +* The `crate` keyword refers to the current crate. +* Uniform paths variant: Paths work uniformly in both `use` declarations and in + other code. Paths work uniformly both in the top-level module and in + submodules. Any path may start with a crate, with `crate`, `super`, or + `self`, or with a local name relative to the current module. +* Anchored use paths variant: Paths in `use` declarations always start with a + crate name, or with `crate`, `super`, or `self`. Paths in code other than + `use` declarations may also start with names relative to the current module. * A `foo.rs` and `foo/` subdirectory may coexist; `mod.rs` is no longer needed when placing submodules in a subdirectory. @@ -60,14 +73,142 @@ keep doing what you were doing there as well. One other use for `extern crate` was to import macros; that's no longer needed. Check [the macro section](2018/transitioning/modules/macros.html) for more. -### Absolute paths begin with `crate` or the crate name +### The `crate` keyword refers to the current crate. + +In `use` declarations and in other code, you can refer to the root of the +current crate with the `crate::` prefix. For instance, `crate::foo::bar` will +always refer to the name `bar` inside the module `foo`, from anywhere else in +the same crate. + +The prefix `::` previously referred to either the crate root or an external +crate; it now unambiguously refers to an external crate. For instance, +`::foo::bar` always refers to the name `bar` inside the external crate `foo`. + +### Uniform paths variant + +The uniform paths variant of Rust 2018 simplifies and unifies path handling +compared to Rust 2015. In Rust 2015, paths work differently in `use` +declarations than they do elsewhere. In particular, paths in `use` +declarations would always start from the crate root, while paths in other code +implicitly started from the current module. Those differences didn't have any +effect in the top-level module, which meant that everything would seem +straightforward until working on a project large enough to have submodules. + +In the uniform paths variant of Rust 2018, paths in `use` declarations and in +other code always work the same way, both in the top-level module and in any +submodule. You can always use a relative path from the current module, a path +starting from an external crate name, or a path starting with `crate`, `super`, +or `self`. + +Code that looked like this: + +```rust,ignore +// Rust 2015 + +extern crate futures; + +use futures::Future; + +mod foo { + pub struct Bar; +} + +use foo::Bar; + +fn my_poll() -> futures::Poll { ... } + +enum SomeEnum { + V1(usize), + V2(String), +} + +fn func() { + let five = std::sync::Arc::new(5); + use SomeEnum::*; + match ... { + V1(i) => { ... } + V2(s) => { ... } + } +} +``` + +will look exactly the same in Rust 2018, except that you can delete the `extern +crate` line: + +```rust,ignore +// Rust 2018 (uniform paths variant) + +use futures::Future; + +mod foo { + pub struct Bar; +} + +use foo::Bar; + +fn my_poll() -> futures::Poll { ... } + +enum SomeEnum { + V1(usize), + V2(String), +} + +fn func() { + let five = std::sync::Arc::new(5); + use SomeEnum::*; + match ... { + V1(i) => { ... } + V2(s) => { ... } + } +} +``` + +With Rust 2018, however, the same code will also work completely unmodified in +a submodule: + +```rust,ignore +// Rust 2018 (uniform paths variant) + +mod submodule { + use futures::Future; -In Rust 2018, paths in `use` statements *must* begin with one of: + mod foo { + pub struct Bar; + } -- A crate name -- `crate` for the current crate's root -- `self` for the current module's root -- `super` for the current module's parent + use foo::Bar; + + fn my_poll() -> futures::Poll { ... } + + enum SomeEnum { + V1(usize), + V2(String), + } + + fn func() { + let five = std::sync::Arc::new(5); + use SomeEnum::*; + match ... { + V1(i) => { ... } + V2(s) => { ... } + } + } +} +``` + +This makes it easy to move code around in a project, and avoids introducing +additional complexity to multi-module projects. + +If a path is ambiguous, such as if you have an external crate and a local +module or item with the same name, you'll get an error, and you'll need to +either rename one of the conflicting names or explicitly disambiguate the path. +To explicitly disambiguate a path, use `::name` for an external crate name, or +`self::name` for a local module or item. + +### Anchored use paths variant + +In the anchored use paths variant of Rust 2018, paths in `use` declarations +*must* begin with a crate name, `crate`, `self`, or `super`. Code that looked like this: @@ -79,7 +220,7 @@ extern crate futures; use futures::Future; mod foo { - struct Bar; + pub struct Bar; } use foo::Bar; @@ -88,22 +229,22 @@ use foo::Bar; Now looks like this: ```rust,ignore -// Rust 2018 +// Rust 2018 (anchored use paths variant) // 'futures' is the name of a crate use futures::Future; mod foo { - struct Bar; + pub struct Bar; } // 'crate' means the current crate use crate::foo::Bar; ``` -In addition, all of these path forms are available outside of `use` statements -as well, which eliminates many sources of confusion. Consider this code in Rust -2015: +In addition, all of these path forms are available outside of `use` +declarations as well, which eliminates many sources of confusion. Consider this +code in Rust 2015: ```rust,ignore // Rust 2015 @@ -133,7 +274,7 @@ mod submodule { In the `futures` example, the `my_poll` function signature is incorrect, because `submodule` contains no items named `futures`; that is, this path is considered relative. But because -`use` is absolute, `use futures::` works even though a lone `futures::` doesn't! With `std` +`use` is anchored, `use futures::` works even though a lone `futures::` doesn't! With `std` it can be even more confusing, as you never wrote the `extern crate std;` line at all. So why does it work in `main` but not in a submodule? Same thing: it's a relative path because it's not in a `use` declaration. `extern crate std;` is inserted at the crate root, so @@ -142,26 +283,26 @@ it's fine in `main`, but it doesn't exist in the submodule at all. Let's look at how this change affects things: ```rust,ignore -// Rust 2018 +// Rust 2018 (anchored use paths variant) // no more `extern crate futures;` mod submodule { - // 'futures' is the name of a crate, so this is absolute and works + // 'futures' is the name of a crate, so this is anchored and works use futures::Future; - // 'futures' is the name of a crate, so this is absolute and works + // 'futures' is the name of a crate, so this is anchored and works fn my_poll() -> futures::Poll { ... } } fn main() { - // 'std' is the name of a crate, so this is absolute and works + // 'std' is the name of a crate, so this is anchored and works let five = std::sync::Arc::new(5); } mod submodule { fn function() { - // 'std' is the name of a crate, so this is absolute and works + // 'std' is the name of a crate, so this is anchored and works let five = std::sync::Arc::new(5); } } @@ -169,7 +310,6 @@ mod submodule { Much more straightforward. -**Note**: an alternative syntax is also under consideration: writing `::some::Local` rather than `crate::some::Local`. If you have thoughts about this alternative, please leave a comment on [the tracking issue](https://github.com/rust-lang/rust/issues/44660) or start a thread on the [edition feedback category](https://internals.rust-lang.org/c/edition-2018-feedback). ### No more `mod.rs`