Merge remote-tracking branch 'o11c/modules'

This commit is contained in:
Brian Anderson 2014-04-22 16:09:12 -07:00
commit 8acdafbe55
1 changed files with 122 additions and 0 deletions

View File

@ -0,0 +1,122 @@
- Start Date: 2014-03-23
- RFC PR #:
- Rust Issue #:
# Summary
A proposal for making the `mod` keyword do what everybody expects, and make
it easier to manage multiple modules in a directory. The actual semantics of
the `use` keyword would not significantly change, but the practical use
would be tightened.
# Motivation
Note: in this proposal, I omit most use of the `pub` keyword, even if is
required. When I speak of "public", I refer only to conceptual visibility.
Frequently, newcomers to the language try to put a `mod` statement in
every file that accesses a module. Partilarly, they expect `mod` to work
like C/C++ `#include` or python `import`. C++ `using` or python `from x import`
only do a single duty of bringing a name into scope, but Rust's `use` does
the equivalent of both `#include` and `using`, and there is no equivalent
to Rust's `mod` at all.
Being confusing to newcomers is, in itself, a bug. But the strange purpose
of Rust's `mod` is also harmful even if you know what it does. Consider the
case when you have many files in a module. Several of the files in this
module require some shared routines. Currently, the mod.rs is required
to not only list the `mod` statements for the "public" modules (which is
reasonable, though some might argue in favor of `mod *;` to catch them all),
but also all of the private details that those modules use.
Apparently, the current way is not confusing if coming from Javascript,
but Javascript is an example of good *marketing*, not good *design*.
My proposal is mostly based on the way Python does it.
# Detailed design
## Source layout
- src/main.rs
`mod fish;`
`mod bird;`
`mod penguin;`
- src/fish.rs
- src/bird.rs
`mod penguin;`
- src/penguin/
- src/penguin/mod.rs
`mod foo;`
`mod bar;`
`use self::foo::popular_function;`
`use super::bird;`
`use ::fish::swim;`
- src/penguin/foo.rs
`mod bar;`
`mod detail;`
- src/penguin/bar.rs
`mod detail;`
- src/penguin/detail.rs
`use self::bar;` (\*)
`use super::fish;` (\*)
(Those (\*)s would need an extra super:: in alternative #3.)
## Stop
Go back and look at the source layout again.
I bet you (whether familiar with Rust, or only with other languages)
understood *exactly* what that source layout means without having to read
any documentation at all. Documentation is *never* a substitute for being
obvious.
## Suggested Approach
First, introduce the (transparent) concept of a 'package'. A package is a
collection of modules from one directory. A crate has a root package.
A package may contain subpackages, which are also modules.
One of the modules in a package is considered the root module. For the
root package, this is main.rs or lib.rs; for subpackages this is mod.rs.
All of the visible names in the root module are also visible when the
package is viewed as a module. Besides the obvious subpackage case, this
is important for locating `fn main`, and can also happen with `super::`.
To avoid cycles during compilation, the modules may be completely loaded,
or just registered to be loaded when done with the current load
(alternatively, the "return early" method may be used).
When actually loading a file, if the compiler see `mod foo` at any point -
even `mod bar { mod foo; }` - it tries to add foo from the current
directory. If foo/mod.rs exists, it is added as a new package (just like
the root package was), otherwise it is added as a module.
Note that any modules in a package that are not directly visible from its
root module will not be directly visible from the package when the package
is used as a module. With the example layout, `::penguin::detail` does not
exist (but `::penguin::foo::detail` and `::penguin::bar::detail` do - if they
didn't `pub` mod/use it, this has the benefits of Java's package-private).
# Alternatives
- Do nothing. Insist to the newcomers "it'll be less confusing later".
- Just eliminate `mod` entirely. Automatically find the right filename
when `use` is used (this is basically how Java imports work).
- Fix the meaning of `mod`, but don't think about 'package'. This could
work, but has a slightly pointless meaning for `self::` and `super::`
# Unresolved questions
All of these questions can be put off until after this RFC is implemented,
though due attention should be given to the first.
- Should `use foo::...` default to `use self::foo::...` or `use ::foo::...`
I'm fond of defaulting `self::`, but rust currently does `::`.
Perhaps it should be forbidden entirely (or gated) for a while?
- Are there any additional improvements that could be made for multiple
crates? (make another RFC after this one is implemented).
- Should `mod *;` be added so a root module need not list all the .rs files?
- Should there be a way to not have a mod.rs at all?
- Should `mod foo { }` be feature-gated?