Skip to content

Commit

Permalink
Update path clarity to reflect the preview period
Browse files Browse the repository at this point in the history
Fixes #62
  • Loading branch information
steveklabnik committed Sep 18, 2018
1 parent c5f4437 commit cf51fb7
Showing 1 changed file with 137 additions and 142 deletions.
279 changes: 137 additions & 142 deletions src/rust-2018/module-system/path-clarity.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Path clarity

![Minimum Rust version: nightly](https://img.shields.io/badge/Minimum%20Rust%20Version-nightly-red.svg)
![Minimum Rust version: nightly](https://img.shields.io/badge/Minimum%20Rust%20Version-nightly-red.svg) for "uniform paths"

The module system is often one of the hardest things for people new to Rust. Everyone
has their own things that take time to master, of course, but there's a root
Expand All @@ -12,34 +13,22 @@ 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.

To test Rust 2018 with the new "uniform paths" variant, put
`#![feature(uniform_paths)]` at the top of your `lib.rs` or
`main.rs`.

Here's a brief summary:

* `extern crate` is no longer needed
* 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.
* Absolute paths begin with a crate name, where the keyword `crate`
refers to the current crate.
* A `foo.rs` and `foo/` subdirectory may coexist; `mod.rs` is no longer needed
when placing submodules in a subdirectory.

These may seem like arbitrary new rules when put this way, but the mental
model is now significantly simplified overall. Read on for more details!

> Additionally, in nightly, there's an additional possible tweak to paths
> called "Uniform paths". This is backwards compatible with the new path
> changes. Uniform paths have a dedicated section at the end of this guide.
## More details

Let's talk about each new feature in turn.
Expand Down Expand Up @@ -109,7 +98,136 @@ 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
### Changes to paths

In Rust 2018, paths in `use` declarations *must* begin with a crate name,
`crate`, `self`, or `super`.

Code that looked like this:

```rust,ignore
// Rust 2015
extern crate futures;
use futures::Future;
mod foo {
pub struct Bar;
}
use foo::Bar;
```

Now looks like this:

```rust,ignore
// Rust 2018
// 'futures' is the name of a crate
use futures::Future;
mod foo {
pub struct Bar;
}
// 'crate' means the current crate
use crate::foo::Bar;
```

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
extern crate futures;
mod submodule {
// this works!
use futures::Future;
// so why doesn't this work?
fn my_poll() -> futures::Poll { ... }
}
fn main() {
// this works
let five = std::sync::Arc::new(5);
}
mod submodule {
fn function() {
// ... so why doesn't this work
let five = std::sync::Arc::new(5);
}
}
```

> In real code, you couldn't repeat `mod submodule`, and `function` would be defined
> in the first `mod` block.
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. `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 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
// no more `extern crate futures;`
mod submodule {
// 'futures' is the name of a crate, so this works
use futures::Future;
// 'futures' is the name of a crate, so this works
fn my_poll<T, E>() -> futures::Poll {
unimplemented!()
}
fn function() {
// 'std' is the name of a crate, so this works
let five = std::sync::Arc::new(5);
}
}
fn main() {
// 'std' is the name of a crate, so this works
let five = std::sync::Arc::new(5);
}
```

Much more straightforward.

### No more `mod.rs`

In Rust 2015, if you have a submodule:

```rust,ignore
mod foo;
```

It can live in `foo.rs` or `foo/mod.rs`. If it has submodules of its own, it
*must* be `foo/mod.rs`. So a `bar` submodule of `foo` would live at
`foo/bar.rs`.

In Rust 2018, `mod.rs` is no longer needed. `foo.rs` can just be `foo.rs`,
and the submodule is still `foo/bar.rs`. This eliminates the special
name, and if you have a bunch of files open in your editor, you can clearly
see their names, instead of having a bunch of tabs named `mod.rs`.


# Uniform paths

> Uniform paths are a nightly-only feature.
The uniform paths variant of Rust 2018 simplifies and unifies path handling
compared to Rust 2015. In Rust 2015, paths work differently in `use`
Expand Down Expand Up @@ -229,126 +347,3 @@ 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:

```rust,ignore
// Rust 2015
extern crate futures;
use futures::Future;
mod foo {
pub struct Bar;
}
use foo::Bar;
```

Now looks like this:

```rust,ignore
// Rust 2018 (anchored use paths variant)
// 'futures' is the name of a crate
use futures::Future;
mod foo {
pub struct Bar;
}
// 'crate' means the current crate
use crate::foo::Bar;
```

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
extern crate futures;
mod submodule {
// this works!
use futures::Future;
// so why doesn't this work?
fn my_poll() -> futures::Poll { ... }
}
fn main() {
// this works
let five = std::sync::Arc::new(5);
}
mod submodule {
fn function() {
// ... so why doesn't this work
let five = std::sync::Arc::new(5);
}
}
```

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 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
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 (anchored use paths variant)
// no more `extern crate futures;`
mod submodule {
// '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 anchored and works
fn my_poll() -> futures::Poll { ... }
}
fn main() {
// '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 anchored and works
let five = std::sync::Arc::new(5);
}
}
```

Much more straightforward.


### No more `mod.rs`

In Rust 2015, if you have a submodule:

```rust,ignore
mod foo;
```

It can live in `foo.rs` or `foo/mod.rs`. If it has submodules of its own, it
*must* be `foo/mod.rs`. So a `bar` submodule of `foo` would live at
`foo/bar.rs`.

In Rust 2018, `mod.rs` is no longer needed. `foo.rs` can just be `foo.rs`,
and the submodule is still `foo/bar.rs`. This eliminates the special
name, and if you have a bunch of files open in your editor, you can clearly
see their names, instead of having a bunch of tabs named `mod.rs`.

0 comments on commit cf51fb7

Please sign in to comment.