# Decoupled Module Improvements

**URL:** <https://internals.rust-lang.org/t/decoupled-module-improvements/5724>\
**Category:** language design\
**Created:** [August 6, 2017, 8:11pm UTC](https://internals.rust-lang.org/t/decoupled-module-improvements/5724 "2017-08-06T20:11:03Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![phaylon](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/phaylon/32/62_2.png) [@phaylon](https://internals.rust-lang.org/u/phaylon)\
**Post date:** [August 6, 2017, 8:11pm UTC](https://internals.rust-lang.org/t/decoupled-module-improvements/5724/1 "2017-08-06T20:11:03Z")

</div>

After my [earlier proposal](https://internals.rust-lang.org/t/my-preferred-module-system-a-fusion-of-earlier-proposals/5718/5) I had the idea that instead of a complete overhaul of semantics, there might be a solution in small, individual changes.

So with the recent discussions and pain points that have been brought up, I have reduced the proposal to two features and an inaction.

I should again point out that all of the ideas are taken from earlier proposals.

# `#![feature(structured_paths)]`

Instead of the current path formats, the following will be recognized:

- `foo::bar` (starting with an identifier) is relative to the current module.
- `::foo::bar` (starting with `::`) is an absolute path in the current crate (see Options below for an alternative).
- `extern::cratename::foo` (starting with `extern::`) is absolute in another crate.
- `super::foo` and `self::foo` as relative prefixes are as they are today.

The `extern::` path is regarded as external crate reference, meaning there is no need to use `extern crate` for it to work. However, the external crate is only available through `extern::` and not as an item in the current crate root.

This feature is not backwards compatible. It would require a feature flag or an epoch-like facility to activate by default.

## Options

- `::foo::bar` could be `crate::foo::bar`, but that is bikeshedding territory as they both would have the same semantics.
- `extern::cratename::` could have different syntax, which would also not change the semantics and is more a visual discussion.

# `#![feature(glob_modules)]`

Keep `mod` working just the way it is currently, but allow the module name to be replaced with `*` causing all submodules of the current module to be loaded, except those loaded explicitly. Renaming is disallowed (for now) with the glob variant.

As an example, assuming the following files:

- `src/lib.rs`
- `src/a.rs`
- `src/b.rs`
- `src/c/mod.rs`
- `src/c/lower.rs`

then the following statement at the crate root `src/lib.rs`:

```
pub(crate) mod *;
pub mod a;

```

will expand to:

```
pub(crate) mod b;
pub(crate) mod c;
pub mod a;

```

Note that it only pulls in direct submodules of the current module, and does not affect any lower submodules.

The rationale for requiring `*` for mod when `extern crate` is no longer necessary is that `extern::` paths don’t introduce items in the module tree, but `mod` does. The `*` is semantically symmetric to the one in a glob import `use foo::*`. Both mark sources of items pulled in the current namespace that aren’t explicitly mentioned.

This feature is backwards compatible and can be enabled by default.

# The `extern crate` situation.

The `structured_paths` feature above means there is no need for an explicit `extern crate foo` if the path `extern::foo` is accessed anywhere.

However, I would propose to leave the `extern crate` as it is right now and not deprecate it because:

- It can still be used to import a crate root as an item into the current module.
- Having it only be an import of a crate root is backwards compatible.
- Existing documentation and examples continue to work in providing a local symbol where `extern crate` is used.
- It doesn’t have to be deprecated now and a separate discussion can be had if it should get hard-removed in future epochs, or linted, or kept.

Edit: Added `extern::cratename::` to Options as visual discussion topic and fixed some prose. Adjusted `extern crate` section to mention possible future deprecation. Thanks to @RalfJung!

---

<div class="post-metadata">

**Author:** ![RalfJung](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ralfjung/32/2415_2.png) [@RalfJung](https://internals.rust-lang.org/u/RalfJung)\
**Post date:** [August 6, 2017, 10:19pm UTC](https://internals.rust-lang.org/t/decoupled-module-improvements/5724/2 "2017-08-06T22:19:41Z")

</div>

> [@phaylon](#):
>
> The latter one is regarded as external crate reference,

The latter here is `self` and `super`, I assume you mean `extern::cratename::foo`.

> [@phaylon](#):
>
> However, I would propose to leave the extern crate as it is right now and not deprecate it because:
> 
> It can still be used to import a crate root as an item into the current module. Having it only be an import of a crate root is backwards compatible. Existing documentation and examples continue to work in providing a local symbol where extern crate is used.

I think `extern crate` should be deprecated -- if only with the goal of pushing people to the new system so that code is more uniform and easier to understand for newcomers. Re-exporting an entire crate inside the current crate should be done deliberately, not "just because `extern crate` is still in the code and this is how things used to work".

In @withoutboats's thread, someone mentioned that `extern::cratename::foo` is a little itchy, and I agree with that. The crate name is not really an item name, yet it appears in a place where usually there would be item names. So, IMHO the `Options` subsection should be extended to not just bikeshed about `::foo` vs `crate::foo` but also about `extern::cratename::foo` vs something else. But again that's just syntax, the semantics stay the same.

Other than that, there's nothing here I object. 😉 I don't have an opinion on `mod *` vs. just loading from the file system. Similarly, you make `use` stay an item like it is now, which I prefer -- but making it just extend the search space for this module (and having some new thing for re-exporting) would also be fine for me. The only thing I really care about is consistency of the way paths are interpreted, and (distant second) consistency in general, e.g. around `use` and `pub use` (in case `pub use` is still a thing).

Btw, one way to make `structured_paths` backwards compatible is to introduce a new keyword -- maybe `import` rather than `use` or so. But now I'm getting way ahead of the discussion, already thinking about a transition path 😉

---

<div class="post-metadata">

**Author:** ![phaylon](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/phaylon/32/62_2.png) [@phaylon](https://internals.rust-lang.org/u/phaylon)\
**Post date:** [August 6, 2017, 10:34pm UTC](https://internals.rust-lang.org/t/decoupled-module-improvements/5724/3 "2017-08-06T22:34:09Z")

</div>

> [@RalfJung](#):
>
> The latter here is self and super, I assume you mean extern::cratename::foo.

Thanks, yes. I fixed that.

> [@RalfJung](#):
>
> I think extern crate should be deprecated – if only with the goal of pushing people to the new system so that code is more uniform and easier to understand for newcomers. Re-exporting an entire crate inside the current crate should be done deliberately, not “just because extern crate is still in the code and this is how things used to work”.

That's certainly possible. I do like that in this scenario, that is a separate discussion. Could be kept for backwards compatibility but with a lint proposing `use extern::cratename` or removing it entirely instead.

> [@RalfJung](#):
>
> In @withoutboats’s thread, someone mentioned that extern::cratename::foo is a little itchy, and I agree with that. The crate name is not really an item name, yet it appears in a place where usually there would be item names. So, IMHO the Options subsection should be extended to not just bikeshed about ::foo vs crate::foo but also about extern::cratename::foo vs something else. But again that’s just syntax, the semantics stay the same.

You're right, I added a note to Options to reflect that.

> [@RalfJung](#):
>
> Other than that, there’s nothing here I object. 😉 I don’t have an opinion on mod \* vs. just loading from the file system. Similarly, you make use stay an item like it is now, which I prefer – but making it just extend the search space for this module (and having some new thing for re-exporting) would also be fine for me. The only thing I really care about is consistency of the way paths are interpreted, and (distant second) consistency in general, e.g. around use and pub use (in case pub use is still a thing).

Yeah, I largely agree on priorities. Of course I'm biased with regards to `mod *` 🙂

> [@RalfJung](#):
>
> Btw, one way to make structured\_paths backwards compatible is to introduce a new keyword – maybe import rather than use or so. But now I’m getting way ahead of the discussion, already thinking about a transition path 😉

Possible, but that would complicate using the paths outside of import statements, since you'd need to disambiguate there too.

---

<div class="post-metadata">

**Author:** ![RalfJung](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ralfjung/32/2415_2.png) [@RalfJung](https://internals.rust-lang.org/u/RalfJung)\
**Post date:** [August 6, 2017, 10:46pm UTC](https://internals.rust-lang.org/t/decoupled-module-improvements/5724/4 "2017-08-06T22:46:54Z")

</div>

> [@phaylon](#):
>
> Possible, but that would complicate using the paths outside of import statements, since you’d need to disambiguate there too.

How that? Nothing changes outside of import statements. Things stay relative. Maybe `::foo` gets deprecated in favor of `crate::foo`, but the rest is just adding new things. Only when people remove `extern crate` and replace it by `use extern::`, they have to also change things eslewhere in their code, but that's fine from a backcompat standpoint.

---

<div class="post-metadata">

**Author:** ![phaylon](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/phaylon/32/62_2.png) [@phaylon](https://internals.rust-lang.org/u/phaylon)\
**Post date:** [August 6, 2017, 10:47pm UTC](https://internals.rust-lang.org/t/decoupled-module-improvements/5724/5 "2017-08-06T22:47:37Z")

</div>

Reading it again, I should clarify: `extern crate` can certainly be deprecated under this scheme without problems. But since their only leftover capacity would be a fancier `use extern::cratename` that decision can stand on its own.

The reasons for not deprecating it are more reasons for not deprecating it within the scope of this proposal.

---

<div class="post-metadata">

**Author:** ![phaylon](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/phaylon/32/62_2.png) [@phaylon](https://internals.rust-lang.org/u/phaylon)\
**Post date:** [August 6, 2017, 10:52pm UTC](https://internals.rust-lang.org/t/decoupled-module-improvements/5724/6 "2017-08-06T22:52:32Z")

</div>

> [@RalfJung](#):
>
> How that? Nothing changes outside of import statements. Things stay relative. Maybe ::foo gets deprecated in favor of crate::foo, but the rest is just adding new things.

I'm not sure I understand, under this proposal `foo` would be relative to the current module, while it is currently looking for `::foo` as well. So you'd have to `use extern::std::io` (or the equivalent) instead of the current `use std::io`. And for other things you'd need a way to do `impl extern::std::Display for ..`.

---

<div class="post-metadata">

**Author:** ![RalfJung](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ralfjung/32/2415_2.png) [@RalfJung](https://internals.rust-lang.org/u/RalfJung)\
**Post date:** [August 6, 2017, 10:57pm UTC](https://internals.rust-lang.org/t/decoupled-module-improvements/5724/7 "2017-08-06T22:57:46Z")

</div>

> [@phaylon](#):
>
> The reasons for not deprecating it are more reasons for not deprecating it within the scope of this proposal.

Note that you can import a crate root as an item even without `extern crate`, use do `use extern::std;`.

So, besides backwards compatibility, I don't see any argument for keeping `extern crate`. Which is exactly the kind of thing that should be deprecated. 🙂

> under this proposal foo would be relative to the current module, while it is currently looking for ::foo as well.

...?

> you’d have to use extern::std::io (or the equivalent) instead of the current use std::io.

Right, which is why I suggested a new keyword. The only currently valid code that changes its meaning under this proposal is `use` with a path not starting with `::`, `self` or `super`.

> [@phaylon](#):
>
> for other things you’d need a way to do impl extern::std::Display for ...

That's backwards compatible.

---

<div class="post-metadata">

**Author:** ![phaylon](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/phaylon/32/62_2.png) [@phaylon](https://internals.rust-lang.org/u/phaylon)\
**Post date:** [August 6, 2017, 11:13pm UTC](https://internals.rust-lang.org/t/decoupled-module-improvements/5724/8 "2017-08-06T23:13:28Z")

</div>

> [@RalfJung](#):
>
> That’s backwards compatible.

I just realized my confusion: I completely forgot that the absolute resolution only applies to use statements, since I always import the namespaces of things I refer to.

So yes, you're fully correct. Having a new keyword instead of use would make it backwards-compatible. Thanks for the reminder.

---

<div class="post-metadata">

**Author:** ![elahn](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/elahn/32/1652_2.png) [@elahn](https://internals.rust-lang.org/u/elahn)\
**Post date:** [August 7, 2017, 8:43pm UTC](https://internals.rust-lang.org/t/decoupled-module-improvements/5724/9 "2017-08-07T20:43:28Z")

</div>

> [@RalfJung](#):
>
> So, besides backwards compatibility, I don’t see any argument for keeping extern crate. Which is exactly the kind of thing that should be deprecated. 🙂

The same argument applies to `self::`, right?

I'm in favour of the semantics of `#![feature(structured_paths)]` with the syntax:

```rust
use ::something_in_crate_root;
use [std]::fmt; // instead of extern::std::fmt

```

Since `[other_crate]::` can be used everywhere and is visually concise, I would never import a crate root.

---

<div class="post-metadata">

**Author:** ![elahn](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/elahn/32/1652_2.png) [@elahn](https://internals.rust-lang.org/u/elahn)\
**Post date:** [August 8, 2017, 7:35pm UTC](https://internals.rust-lang.org/t/decoupled-module-improvements/5724/11 "2017-08-08T19:35:24Z")

</div>

We’ll need a motivation section for `#![feature(structured_paths)]` which overcomes the objections raised. So far I’ve seen:

- Other languages use absolute paths in imports, so doing otherwise would be surprising.
- Numbers show `self::` is relatively rare, so requiring a leading `::` in `use` is burdensome.
- Leading `::` in `use` is ugly.
- Absolute in `use` and relative elsewhere is an easy rule to remember, so that’s not contributing to “path confusion.”

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [March 25, 2019, 8:28am UTC](https://internals.rust-lang.org/t/decoupled-module-improvements/5724/12 "2019-03-25T08:28:53Z")

</div>

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
