Skip to content
This repository was archived by the owner on Oct 9, 2018. It is now read-only.

Commit 4c20877

Browse files
features/modules: clarification & updates
Per Aaron Turon's suggestions, this clarifies much of the wording for modules. Additionally, it adds recommendations about: - Module naming - Header ordering - path directives
1 parent bdbf206 commit 4c20877

File tree

1 file changed

+99
-54
lines changed

1 file changed

+99
-54
lines changed

features/modules.md

Lines changed: 99 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -5,83 +5,128 @@
55
> We should discuss visibility, nesting, `mod.rs`, and any interesting patterns
66
> around modules.
77
8-
## Basic design
8+
#### Naming conventions
9+
> **[OPEN]**
10+
> - Anything else?
11+
> - Are there cases where *not* separating words with underscores is OK,
12+
> or should this be a hard rule?
913
10-
> **[OPEN]** This documents the simple, common pattern of module
11-
> design - but others exist and improvements are appreciated.
14+
- Module names should contain only lowercae letters and underscores.
15+
For example, use `std::io::timer`, not `Std::IO::Timer`.
16+
- Multiple words should be separated by underscores.
17+
Use `std::local_data`, not `std::localData` or `std::localdata`.
1218

13-
The file `mod.rs` in a module defines the base-level imports of the
14-
module. For all except trivial modules (and
15-
[test cases](../testing/README.md)), it is better to keep this in a
16-
separate file.
19+
#### Headers
20+
> **[OPEN]** Is this header organization suggestion valid?
1721
18-
A big use of `mod.rs` is to define a common interface for your module. The
19-
internal structure can be whatever form that you might like, but then
20-
this code will all get re-exported in `mod.rs` to the rest of the world.
22+
Organize module headers as follows:
23+
1. [Imports](../style/imports.md).
24+
1. `mod` declarations.
25+
1. `pub mod` declarations.
2126

22-
This also serves a convenience purpose: users of your module only have
23-
to remember the module name, and you can keep whatever internal
24-
structure is required.
27+
#### Avoid `path` directives
28+
> **[OPEN]** This is hardly ever seen in the Rust codebase (only 4 uses, all in
29+
> `libsyntax`) and seems like overall a bad idea.
2530
26-
For example, say we had the following folder structure:
31+
Avoid using `#[path="..."]` directives except where it is *absolutely*
32+
necessary.
2733

28-
```
29-
myio/mod.rs
30-
/mem.rs
31-
/terminal/mod.rs
32-
```
34+
### Use the module hirearchy to organize APIs into coherent sections
35+
> **[OPEN]**
3336
34-
where we wish to keep `mem.rs` hidden from the outside world, and make
35-
usage of `terminal` an explicit submodule. In `myio/mod.rs` we would
36-
write:
37+
The module hirearchy defines both the public and internal API of your module.
38+
Breaking related functionality into submodules makes it understandable to both
39+
users and contributors to the module.
3740

38-
```rust
39-
// myio/mod.rs
41+
#### Place modules in separate files
42+
> **[OPEN]**
43+
> - "<100 lines" is completely arbitrary, but it's a clearer recommendation
44+
> than "~1 page" or similar suggestions that vary by screen size, etc.
4045
41-
pub use self::mem::MemReader;
46+
For all except very short modules (<100 lines) and [tests](../testing/README.md),
47+
place the module `foo` in a separate file: either `foo.rs` or `foo/mod.rs`,
48+
depending on your needs, rather than declaring it inline like
4249

43-
mod mem;
44-
pub mod terminal;
50+
```rust
51+
pub mod foo {
52+
pub fn bar() { println!("..."); }
53+
/* ... */
54+
}
4555
```
4656

47-
### Export common traits, structs, and enums at the module level
48-
57+
#### Use folders to organize submodules
4958
> **[OPEN]**
5059
51-
In the above example, we re-export `MemReader`, but we might have others
52-
that are common to the whole module, and not just `mem.rs`:
60+
For modules that themselves have submodules, place the module in a separate
61+
folder (e.g., `bar/mod.rs` for a module `bar`) rather than the same directory.
5362

54-
```rust
55-
// myio/mod.rs
63+
Note the structure of
64+
[`std::io`](http://doc.rust-lang.org/std/io/). Many of the submodules lack
65+
children, like
66+
[`io::fs`](http://doc.rust-lang.org/std/io/fs/)
67+
and
68+
[`io::stdio`](http://doc.rust-lang.org/std/io/stdio/).
69+
On the other hand,
70+
[`io::net`](http://doc.rust-lang.org/std/io/net/)
71+
contains submodules, so it lives in a separate folder:
5672

57-
pub enum FileMode { /* ... */ }
58-
pub trait Seek { /* ... */ }
59-
pub struct File { /* ... */ }
73+
```
74+
io/mod.rs
75+
io/extensions.rs
76+
io/fs.rs
77+
io/net/mod.rs
78+
io/net/addrinfo.rs
79+
io/net/ip.rs
80+
io/net/tcp.rs
81+
io/net/udp.rs
82+
io/net/unix.rs
83+
io/pipe.rs
84+
...
6085
```
6186

62-
Then, to use these common traits in submodules:
63-
64-
```rust
65-
// myio/mem.rs
87+
While it is possible to define all of `io` within a single folder, mirroring
88+
the module hirearchy in the directory structure makes submodules of `io::net`
89+
easier to find.
6690

67-
use super::Seek;
91+
#### Top-level definitions
92+
> **[OPEN]**
6893
69-
pub struct MemReader { /* ... */ }
70-
impl MemReader { /* ... */ }
71-
impl Seek for MemReader { /* ... */ }
72-
```
94+
Define or [reexport](http://doc.rust-lang.org/std/io/#reexports) commonly used
95+
definitions at the top level of your module.
7396

74-
Notice how both `Seek` and `MemReader` are both visible from
75-
`myio::Seek` and `myio::MemReader`.
97+
Functionality that is related to the module itself should be defined in
98+
`mod.rs`, while functionality specific to a submodule should live in its
99+
related submodule and be reexported elsewhere.
76100

77-
### Use private modules to hide information
101+
For example,
102+
[`IoError`](http://doc.rust-lang.org/std/io/struct.IoError.html)
103+
is defined in `io/mod.rs`, since it pertains to the entirety of the submodule,
104+
while
105+
[`TcpStream`](http://doc.rust-lang.org/std/io/net/tcp/struct.TcpStream.html)
106+
is defined in `io/net/tcp.rs` and reexported in the `io` module.
78107

108+
### Use internal module hirearchies for hiding implementations
79109
> **[OPEN]**
110+
> - Referencing internal modules from the standard library is subject to
111+
> becoming outdated.
112+
113+
Internal module hirearchies (including private submodules) may be used to
114+
hide implementation details that are not part of the module's API.
80115

81-
This structure lets you achieve the goals of information hiding (the
82-
implementation of `mem` is separate from the `MemReader` in our API) and
83-
making all useful types available for the internal modules.
116+
For example, in [`std::io`](http://doc.rust-lang.org/std/io/), `mod mem`
117+
provides implementations for
118+
[`BufReader`](http://doc.rust-lang.org/std/io/struct.BufReader.html)
119+
and
120+
[`BufWriter`](http://doc.rust-lang.org/std/io/struct.BufWriter.html),
121+
but these are re-exported in `io/mod.rs` at the top level of the module:
122+
123+
```rust
124+
// libstd/io/mod.rs
125+
126+
pub use self::mem::{MemReader, BufReader, MemWriter, BufWriter};
127+
/* ... */
128+
mod mem;
129+
```
84130

85-
It is good practice to keep code that is likely to change hidden in this
86-
manner, and only make public the parts that constitute the module's
87-
interface.
131+
This hides the detail that there even exists a `mod mem` in `io`, and
132+
helps keep code organized while offering freedom to change the implementation.

0 commit comments

Comments
 (0)