Browse files

features/modules: clarification & updates

Per Aaron Turon's suggestions, this clarifies much of the wording for

Additionally, it adds recommendations about:

- Module naming
- Header ordering
- path directives
  • Loading branch information...
1 parent bdbf206 commit 4c208773d48d7512302a0cf01380401edceea354 @nathantypanski nathantypanski committed Jul 2, 2014
Showing with 99 additions and 54 deletions.
  1. +99 −54 features/
@@ -5,83 +5,128 @@
> We should discuss visibility, nesting, ``, and any interesting patterns
> around modules.
-## Basic design
+#### Naming conventions
+> **[OPEN]**
+> - Anything else?
+> - Are there cases where *not* separating words with underscores is OK,
+> or should this be a hard rule?
-> **[OPEN]** This documents the simple, common pattern of module
-> design - but others exist and improvements are appreciated.
+- Module names should contain only lowercae letters and underscores.
+ For example, use `std::io::timer`, not `Std::IO::Timer`.
+- Multiple words should be separated by underscores.
+ Use `std::local_data`, not `std::localData` or `std::localdata`.
-The file `` in a module defines the base-level imports of the
-module. For all except trivial modules (and
-[test cases](../testing/, it is better to keep this in a
-separate file.
+#### Headers
+> **[OPEN]** Is this header organization suggestion valid?
-A big use of `` is to define a common interface for your module. The
-internal structure can be whatever form that you might like, but then
-this code will all get re-exported in `` to the rest of the world.
+Organize module headers as follows:
+ 1. [Imports](../style/
+ 1. `mod` declarations.
+ 1. `pub mod` declarations.
-This also serves a convenience purpose: users of your module only have
-to remember the module name, and you can keep whatever internal
-structure is required.
+#### Avoid `path` directives
+> **[OPEN]** This is hardly ever seen in the Rust codebase (only 4 uses, all in
+> `libsyntax`) and seems like overall a bad idea.
-For example, say we had the following folder structure:
+Avoid using `#[path="..."]` directives except where it is *absolutely*
+ necessary.
- /
- /terminal/
+### Use the module hirearchy to organize APIs into coherent sections
+> **[OPEN]**
-where we wish to keep `` hidden from the outside world, and make
-usage of `terminal` an explicit submodule. In `myio/` we would
+The module hirearchy defines both the public and internal API of your module.
+Breaking related functionality into submodules makes it understandable to both
+users and contributors to the module.
-// myio/
+#### Place modules in separate files
+> **[OPEN]**
+> - "<100 lines" is completely arbitrary, but it's a clearer recommendation
+> than "~1 page" or similar suggestions that vary by screen size, etc.
-pub use self::mem::MemReader;
+For all except very short modules (<100 lines) and [tests](../testing/,
+place the module `foo` in a separate file: either `` or `foo/`,
+depending on your needs, rather than declaring it inline like
-mod mem;
-pub mod terminal;
+pub mod foo {
+ pub fn bar() { println!("..."); }
+ /* ... */
-### Export common traits, structs, and enums at the module level
+#### Use folders to organize submodules
> **[OPEN]**
-In the above example, we re-export `MemReader`, but we might have others
-that are common to the whole module, and not just ``:
+For modules that themselves have submodules, place the module in a separate
+folder (e.g., `bar/` for a module `bar`) rather than the same directory.
-// myio/
+Note the structure of
+[`std::io`]( Many of the submodules lack
+children, like
+On the other hand,
+contains submodules, so it lives in a separate folder:
-pub enum FileMode { /* ... */ }
-pub trait Seek { /* ... */ }
-pub struct File { /* ... */ }
+ io/
+ io/
+ io/net/
+ io/net/
+ io/net/
+ io/net/
+ io/net/
+ io/net/
+ io/
+ ...
-Then, to use these common traits in submodules:
-// myio/
+While it is possible to define all of `io` within a single folder, mirroring
+the module hirearchy in the directory structure makes submodules of `io::net`
+easier to find.
-use super::Seek;
+#### Top-level definitions
+> **[OPEN]**
-pub struct MemReader { /* ... */ }
-impl MemReader { /* ... */ }
-impl Seek for MemReader { /* ... */ }
+Define or [reexport]( commonly used
+definitions at the top level of your module.
-Notice how both `Seek` and `MemReader` are both visible from
-`myio::Seek` and `myio::MemReader`.
+Functionality that is related to the module itself should be defined in
+``, while functionality specific to a submodule should live in its
+related submodule and be reexported elsewhere.
-### Use private modules to hide information
+For example,
+is defined in `io/`, since it pertains to the entirety of the submodule,
+is defined in `io/net/` and reexported in the `io` module.
+### Use internal module hirearchies for hiding implementations
> **[OPEN]**
+> - Referencing internal modules from the standard library is subject to
+> becoming outdated.
+Internal module hirearchies (including private submodules) may be used to
+hide implementation details that are not part of the module's API.
-This structure lets you achieve the goals of information hiding (the
-implementation of `mem` is separate from the `MemReader` in our API) and
-making all useful types available for the internal modules.
+For example, in [`std::io`](, `mod mem`
+provides implementations for
+but these are re-exported in `io/` at the top level of the module:
+// libstd/io/
+pub use self::mem::{MemReader, BufReader, MemWriter, BufWriter};
+/* ... */
+mod mem;
-It is good practice to keep code that is likely to change hidden in this
-manner, and only make public the parts that constitute the module's
+This hides the detail that there even exists a `mod mem` in `io`, and
+helps keep code organized while offering freedom to change the implementation.

0 comments on commit 4c20877

Please sign in to comment.