Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update for uniform_path stabilization. #141

Merged
merged 2 commits into from
Feb 21, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 2 additions & 10 deletions src/rust-2018/edition-changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,8 @@ the 2018 edition compared to the 2015 edition.
- [Non-lexical lifetimes] (future inclusion planned for 2015 edition)
- [At most once] `?` macro repetition operator.
- [Path changes]:
- `use` declarations must begin with:
- `crate` – refers to the current crate.
- `self` – refers to the current module.
- `super` – refers to the parent module.
- An external crate name.
- `::` – must be followed by an external crate name. This is required
if an external crate has the same name as an in-scope item, to catch
possible ambiguities with [uniform paths] (which is planned for
inclusion soon [#55618]).
- [Uniform paths] in `use` declarations.
- Paths staring with `::` must be followed with an external crate.
- Paths in `pub(in path)` visibility modifiers must start with `crate`,
`self`, or `super`.
- [Anonymous trait function parameters] are not allowed.
Expand All @@ -35,7 +28,6 @@ the 2018 edition compared to the 2015 edition.
- `cargo install` for the current directory is no longer allowed, you must
specify `cargo install --path .` to install the current package.

[#55618]: https://github.com/rust-lang/rust/issues/55618
[Anonymous trait function parameters]: rust-2018/trait-system/no-anon-params.html
[At most once]: rust-2018/macros/at-most-once.html
[Non-lexical lifetimes]: rust-2018/ownership-and-lifetimes/non-lexical-lifetimes.html
Expand Down
135 changes: 35 additions & 100 deletions src/rust-2018/module-system/path-clarity.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# Path clarity

![Minimum Rust version: 1.31](https://img.shields.io/badge/Minimum%20Rust%20Version-1.31-brightgreen.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 @@ -17,18 +16,15 @@ Here's a brief summary:

* `extern crate` is no longer needed in 99% of circumstances.
* The `crate` keyword refers to the current crate.
* Absolute paths begin with a crate name, where the keyword `crate`
refers to the current crate.
* Paths may start with a crate name, even within submodules.
* Paths starting with `::` must reference an external crate.
* A `foo.rs` and `foo/` subdirectory may coexist; `mod.rs` is no longer needed
when placing submodules in a subdirectory.
* `use` declarations take [uniform paths](#uniform-paths).
Centril marked this conversation as resolved.
Show resolved Hide resolved

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 @@ -124,122 +120,61 @@ 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`.

### Changes to paths

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

Code that looked like this:
Previously, using an external crate in a module without a `use` import
required a leading `::` on the path.

```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
extern crate chrono;

// '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);
fn foo() {
// this works in the crate root
let x = chrono::Utc::now();
}

mod submodule {
fn function() {
// ... so why doesn't this work
let five = std::sync::Arc::new(5);
// but in a submodule it requires a leading :: if not imported with `use`
let x = ::chrono::Utc::now();
}

// unlike expressions, `use` paths were allowed to reference crates directly
use chrono::Local;
}
```

> 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:
Now, extern crate names are in scope in the entire crate, including
submodules.

```rust,ignore
// Rust 2018

// no more `extern crate futures;`
fn foo() {
// this works in the crate root
let x = chrono::Utc::now();
}

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);
// crates may be referenced directly, even in submodules
let x = chrono::Utc::now();
}
}

fn main() {
// 'std' is the name of a crate, so this works
let five = std::sync::Arc::new(5);
// `use` paths have the same path style
use chrono::Local;
}
```

Much more straightforward.

### No more `mod.rs`

In Rust 2015, if you have a submodule:

```rust,ignore
/// foo.rs
/// or
/// foo.rs
/// or
/// foo/mod.rs

mod foo;
Expand All @@ -249,10 +184,10 @@ 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.
In Rust 2018, `mod.rs` is no longer needed.

```rust,ignore
/// foo.rs
/// foo.rs
/// foo/bar.rs

mod foo;
Expand All @@ -268,21 +203,21 @@ see their names, instead of having a bunch of tabs named `mod.rs`.

# Uniform paths

> Uniform paths are a nightly-only feature.
![Minimum Rust version: 1.32](https://img.shields.io/badge/Minimum%20Rust%20Version-1.32-brightgreen.svg)

The uniform paths variant of Rust 2018 simplifies and unifies path handling
Centril marked this conversation as resolved.
Show resolved Hide resolved
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
implicitly started from the current scope. 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
Centril marked this conversation as resolved.
Show resolved Hide resolved
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`.
other code almost always work the same way, both in the top-level module and
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "almost" bit here will leave the reader wondering...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😆 I think I have a list of some of the differences, but I don't think it is complete, and the differences are usually quite obscure. Definitely reference-only material. It does briefly mention at the bottom of the section about ambiguities, which is one of the differences. I just felt that "always" was making a strong assertion that wasn't true.

Copy link
Contributor

@Centril Centril Jan 30, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe: "paths in use declarations and in other code work the same way, ..." (i.e. just remove "always").

This is less "100% sure" but also doesn't say "maybe, we are not sure".

in any submodule. You can use a relative path from the current scope, a path
starting from an external crate name, or a path starting with `crate`,
`super`, or `self`.

Code that looked like this:

Expand Down