Skip to content

Commit c00c8f5

Browse files
committed
RFC: unsurprising module imports
1 parent 1245e64 commit c00c8f5

File tree

1 file changed

+122
-0
lines changed

1 file changed

+122
-0
lines changed

active/0000-module-imports.md

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
- Start Date: 2014-03-23
2+
- RFC PR #:
3+
- Rust Issue #:
4+
5+
# Summary
6+
7+
A proposal for making the `mod` keyword do what everybody expects, and make
8+
it easier to manage multiple modules in a directory. The actual semantics of
9+
the `use` keyword would not significantly change, but the practical use
10+
would be tightened.
11+
12+
# Motivation
13+
14+
Note: in this proposal, I omit most use of the `pub` keyword, even if is
15+
required. When I speak of "public", I refer only to conceptual visibility.
16+
17+
Frequently, newcomers to the language try to put a `mod` statement in
18+
every file that accesses a module. Partilarly, they expect `mod` to work
19+
like C/C++ `#include` or python `import`. C++ `using` or python `from x import`
20+
only do a single duty of bringing a name into scope, but Rust's `use` does
21+
the equivalent of both `#include` and `using`, and there is no equivalent
22+
to Rust's `mod` at all.
23+
24+
Being confusing to newcomers is, in itself, a bug. But the strange purpose
25+
of Rust's `mod` is also harmful even if you know what it does. Consider the
26+
case when you have many files in a module. Several of the files in this
27+
module require some shared routines. Currently, the mod.rs is required
28+
to not only list the `mod` statements for the "public" modules (which is
29+
reasonable, though some might argue in favor of `mod *;` to catch them all),
30+
but also all of the private details that those modules use.
31+
32+
Apparently, the current way is not confusing if coming from Javascript,
33+
but Javascript is an example of good *marketing*, not good *design*.
34+
35+
My proposal is mostly based on the way Python does it.
36+
37+
# Detailed design
38+
39+
## Source layout
40+
41+
- src/main.rs
42+
`mod fish;`
43+
`mod bird;`
44+
`mod penguin;`
45+
- src/fish.rs
46+
- src/bird.rs
47+
`mod penguin;`
48+
- src/penguin/
49+
- src/penguin/mod.rs
50+
`mod foo;`
51+
`mod bar;`
52+
`use self::foo::popular_function;`
53+
`use super::bird;`
54+
`use ::fish::swim;`
55+
- src/penguin/foo.rs
56+
`mod bar;`
57+
`mod detail;`
58+
- src/penguin/bar.rs
59+
`mod detail;`
60+
- src/penguin/detail.rs
61+
`use self::bar;` (\*)
62+
`use super::fish;` (\*)
63+
64+
(Those (\*)s would need an extra super:: in alternative #3.)
65+
66+
## Stop
67+
68+
Go back and look at the source layout again.
69+
70+
I bet you (whether familiar with Rust, or only with other languages)
71+
understood *exactly* what that source layout means without having to read
72+
any documentation at all. Documentation is *never* a substitute for being
73+
obvious.
74+
75+
## Suggested Approach
76+
77+
First, introduce the (transparent) concept of a 'package'. A package is a
78+
collection of modules from one directory. A crate has a root package.
79+
A package may contain subpackages, which are also modules.
80+
81+
One of the modules in a package is considered the root module. For the
82+
root package, this is main.rs or lib.rs; for subpackages this is mod.rs.
83+
All of the visible names in the root module are also visible when the
84+
package is viewed as a module. Besides the obvious subpackage case, this
85+
is important for locating `fn main`, and can also happen with `super::`.
86+
87+
To avoid cycles during compilation, the modules may be completely loaded,
88+
or just registered to be loaded when done with the current load
89+
(alternatively, the "return early" method may be used).
90+
91+
When actually loading a file, if the compiler see `mod foo` at any point -
92+
even `mod bar { mod foo; }` - it tries to add foo from the current
93+
directory. If foo/mod.rs exists, it is added as a new package (just like
94+
the root package was), otherwise it is added as a module.
95+
96+
Note that any modules in a package that are not directly visible from its
97+
root module will not be directly visible from the package when the package
98+
is used as a module. With the example layout, `::penguin::detail` does not
99+
exist (but `::penguin::foo::detail` and `::penguin::bar::detail` do - if they
100+
didn't `pub` mod/use it, this has the benefits of Java's package-private).
101+
102+
# Alternatives
103+
104+
- Do nothing. Insist to the newcomers "it'll be less confusing later".
105+
- Just eliminate `mod` entirely. Automatically find the right filename
106+
when `use` is used (this is basically how Java imports work).
107+
- Fix the meaning of `mod`, but don't think about 'package'. This could
108+
work, but has a slightly pointless meaning for `self::` and `super::`
109+
110+
# Unresolved questions
111+
112+
All of these questions can be put off until after this RFC is implemented,
113+
though due attention should be given to the first.
114+
115+
- Should `use foo::...` default to `use self::foo::...` or `use ::foo::...`
116+
I'm fond of defaulting `self::`, but rust currently does `::`.
117+
Perhaps it should be forbidden entirely (or gated) for a while?
118+
- Are there any additional improvements that could be made for multiple
119+
crates? (make another RFC after this one is implemented).
120+
- Should `mod *;` be added so a root module need not list all the .rs files?
121+
- Should there be a way to not have a mod.rs at all?
122+
- Should `mod foo { }` be feature-gated?

0 commit comments

Comments
 (0)