Skip to content

Commit 1da7f77

Browse files
authored
Merge pull request #74 from joshtriplett/relative-paths
path-clarity: Document new uniform paths variant
2 parents 64123a1 + 42654b6 commit 1da7f77

File tree

1 file changed

+161
-21
lines changed

1 file changed

+161
-21
lines changed

src/rust-2018/path-clarity.md

+161-21
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,24 @@ As such, the 2018 edition of Rust introduces a few new module system
1212
features, but they end up *simplifying* the module system, to make it more
1313
clear as to what is going on.
1414

15+
Note: During the 2018 edition preview, there are two variants of the module
16+
system under consideration, the "uniform paths" variant and the "anchored use
17+
paths" variant. Most of these changes apply to both variants; the two variant
18+
sections call out the differences between the two. We encourage testing of the
19+
new "uniform paths" variant introduced in edition preview 2. The release of
20+
Rust 2018 will stabilize one of these two variants and drop the other.
21+
1522
Here's a brief summary:
1623

1724
* `extern crate` is no longer needed
18-
* Absolute paths begin with a crate name, where the keyword `crate`
19-
refers to the current crate.
25+
* The `crate` keyword refers to the current crate.
26+
* Uniform paths variant: Paths work uniformly in both `use` declarations and in
27+
other code. Paths work uniformly both in the top-level module and in
28+
submodules. Any path may start with a crate, with `crate`, `super`, or
29+
`self`, or with a local name relative to the current module.
30+
* Anchored use paths variant: Paths in `use` declarations always start with a
31+
crate name, or with `crate`, `super`, or `self`. Paths in code other than
32+
`use` declarations may also start with names relative to the current module.
2033
* A `foo.rs` and `foo/` subdirectory may coexist; `mod.rs` is no longer needed
2134
when placing submodules in a subdirectory.
2235

@@ -60,14 +73,142 @@ keep doing what you were doing there as well.
6073
One other use for `extern crate` was to import macros; that's no longer needed.
6174
Check [the macro section](2018/transitioning/modules/macros.html) for more.
6275

63-
### Absolute paths begin with `crate` or the crate name
76+
### The `crate` keyword refers to the current crate.
77+
78+
In `use` declarations and in other code, you can refer to the root of the
79+
current crate with the `crate::` prefix. For instance, `crate::foo::bar` will
80+
always refer to the name `bar` inside the module `foo`, from anywhere else in
81+
the same crate.
82+
83+
The prefix `::` previously referred to either the crate root or an external
84+
crate; it now unambiguously refers to an external crate. For instance,
85+
`::foo::bar` always refers to the name `bar` inside the external crate `foo`.
86+
87+
### Uniform paths variant
88+
89+
The uniform paths variant of Rust 2018 simplifies and unifies path handling
90+
compared to Rust 2015. In Rust 2015, paths work differently in `use`
91+
declarations than they do elsewhere. In particular, paths in `use`
92+
declarations would always start from the crate root, while paths in other code
93+
implicitly started from the current module. Those differences didn't have any
94+
effect in the top-level module, which meant that everything would seem
95+
straightforward until working on a project large enough to have submodules.
96+
97+
In the uniform paths variant of Rust 2018, paths in `use` declarations and in
98+
other code always work the same way, both in the top-level module and in any
99+
submodule. You can always use a relative path from the current module, a path
100+
starting from an external crate name, or a path starting with `crate`, `super`,
101+
or `self`.
102+
103+
Code that looked like this:
104+
105+
```rust,ignore
106+
// Rust 2015
107+
108+
extern crate futures;
109+
110+
use futures::Future;
111+
112+
mod foo {
113+
pub struct Bar;
114+
}
115+
116+
use foo::Bar;
117+
118+
fn my_poll() -> futures::Poll { ... }
119+
120+
enum SomeEnum {
121+
V1(usize),
122+
V2(String),
123+
}
124+
125+
fn func() {
126+
let five = std::sync::Arc::new(5);
127+
use SomeEnum::*;
128+
match ... {
129+
V1(i) => { ... }
130+
V2(s) => { ... }
131+
}
132+
}
133+
```
134+
135+
will look exactly the same in Rust 2018, except that you can delete the `extern
136+
crate` line:
137+
138+
```rust,ignore
139+
// Rust 2018 (uniform paths variant)
140+
141+
use futures::Future;
142+
143+
mod foo {
144+
pub struct Bar;
145+
}
146+
147+
use foo::Bar;
148+
149+
fn my_poll() -> futures::Poll { ... }
150+
151+
enum SomeEnum {
152+
V1(usize),
153+
V2(String),
154+
}
155+
156+
fn func() {
157+
let five = std::sync::Arc::new(5);
158+
use SomeEnum::*;
159+
match ... {
160+
V1(i) => { ... }
161+
V2(s) => { ... }
162+
}
163+
}
164+
```
165+
166+
With Rust 2018, however, the same code will also work completely unmodified in
167+
a submodule:
168+
169+
```rust,ignore
170+
// Rust 2018 (uniform paths variant)
171+
172+
mod submodule {
173+
use futures::Future;
64174
65-
In Rust 2018, paths in `use` statements *must* begin with one of:
175+
mod foo {
176+
pub struct Bar;
177+
}
66178
67-
- A crate name
68-
- `crate` for the current crate's root
69-
- `self` for the current module's root
70-
- `super` for the current module's parent
179+
use foo::Bar;
180+
181+
fn my_poll() -> futures::Poll { ... }
182+
183+
enum SomeEnum {
184+
V1(usize),
185+
V2(String),
186+
}
187+
188+
fn func() {
189+
let five = std::sync::Arc::new(5);
190+
use SomeEnum::*;
191+
match ... {
192+
V1(i) => { ... }
193+
V2(s) => { ... }
194+
}
195+
}
196+
}
197+
```
198+
199+
This makes it easy to move code around in a project, and avoids introducing
200+
additional complexity to multi-module projects.
201+
202+
If a path is ambiguous, such as if you have an external crate and a local
203+
module or item with the same name, you'll get an error, and you'll need to
204+
either rename one of the conflicting names or explicitly disambiguate the path.
205+
To explicitly disambiguate a path, use `::name` for an external crate name, or
206+
`self::name` for a local module or item.
207+
208+
### Anchored use paths variant
209+
210+
In the anchored use paths variant of Rust 2018, paths in `use` declarations
211+
*must* begin with a crate name, `crate`, `self`, or `super`.
71212

72213
Code that looked like this:
73214

@@ -79,7 +220,7 @@ extern crate futures;
79220
use futures::Future;
80221
81222
mod foo {
82-
struct Bar;
223+
pub struct Bar;
83224
}
84225
85226
use foo::Bar;
@@ -88,22 +229,22 @@ use foo::Bar;
88229
Now looks like this:
89230

90231
```rust,ignore
91-
// Rust 2018
232+
// Rust 2018 (anchored use paths variant)
92233
93234
// 'futures' is the name of a crate
94235
use futures::Future;
95236
96237
mod foo {
97-
struct Bar;
238+
pub struct Bar;
98239
}
99240
100241
// 'crate' means the current crate
101242
use crate::foo::Bar;
102243
```
103244

104-
In addition, all of these path forms are available outside of `use` statements
105-
as well, which eliminates many sources of confusion. Consider this code in Rust
106-
2015:
245+
In addition, all of these path forms are available outside of `use`
246+
declarations as well, which eliminates many sources of confusion. Consider this
247+
code in Rust 2015:
107248

108249
```rust,ignore
109250
// Rust 2015
@@ -133,7 +274,7 @@ mod submodule {
133274

134275
In the `futures` example, the `my_poll` function signature is incorrect, because `submodule`
135276
contains no items named `futures`; that is, this path is considered relative. But because
136-
`use` is absolute, `use futures::` works even though a lone `futures::` doesn't! With `std`
277+
`use` is anchored, `use futures::` works even though a lone `futures::` doesn't! With `std`
137278
it can be even more confusing, as you never wrote the `extern crate std;` line at all. So
138279
why does it work in `main` but not in a submodule? Same thing: it's a relative path because
139280
it's not in a `use` declaration. `extern crate std;` is inserted at the crate root, so
@@ -142,34 +283,33 @@ it's fine in `main`, but it doesn't exist in the submodule at all.
142283
Let's look at how this change affects things:
143284

144285
```rust,ignore
145-
// Rust 2018
286+
// Rust 2018 (anchored use paths variant)
146287
147288
// no more `extern crate futures;`
148289
149290
mod submodule {
150-
// 'futures' is the name of a crate, so this is absolute and works
291+
// 'futures' is the name of a crate, so this is anchored and works
151292
use futures::Future;
152293
153-
// 'futures' is the name of a crate, so this is absolute and works
294+
// 'futures' is the name of a crate, so this is anchored and works
154295
fn my_poll() -> futures::Poll { ... }
155296
}
156297
157298
fn main() {
158-
// 'std' is the name of a crate, so this is absolute and works
299+
// 'std' is the name of a crate, so this is anchored and works
159300
let five = std::sync::Arc::new(5);
160301
}
161302
162303
mod submodule {
163304
fn function() {
164-
// 'std' is the name of a crate, so this is absolute and works
305+
// 'std' is the name of a crate, so this is anchored and works
165306
let five = std::sync::Arc::new(5);
166307
}
167308
}
168309
```
169310

170311
Much more straightforward.
171312

172-
**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).
173313

174314
### No more `mod.rs`
175315

0 commit comments

Comments
 (0)