about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBrian Anderson <banderson@mozilla.com>2012-10-06 22:23:16 -0700
committerBrian Anderson <banderson@mozilla.com>2012-10-06 22:24:15 -0700
commitd5d774124730ee363620c6e4ec5bf65deea2385c (patch)
treeafe2f61bafa74986678ef4d697cca21b7a237268
parentf5c95de212d7851c7f8788a328455ed381e38978 (diff)
downloadrust-d5d774124730ee363620c6e4ec5bf65deea2385c.tar.gz
rust-d5d774124730ee363620c6e4ec5bf65deea2385c.zip
Overhaul mods and crates section of tutorial
-rw-r--r--doc/lib/codemirror-rust.js2
-rw-r--r--doc/tutorial.md315
2 files changed, 154 insertions, 163 deletions
diff --git a/doc/lib/codemirror-rust.js b/doc/lib/codemirror-rust.js
index 02f2c603955..727882d3099 100644
--- a/doc/lib/codemirror-rust.js
+++ b/doc/lib/codemirror-rust.js
@@ -9,7 +9,7 @@ CodeMirror.defineMode("rust", function() {
     "as": "op", "true": "atom", "false": "atom", "assert": "op", "check": "op",
     "claim": "op", "extern": "ignore", "unsafe": "ignore", "import": "else-style",
     "export": "else-style", "copy": "op", "log": "op",
-    "use": "op", "self": "atom"
+    "use": "op", "self": "atom", "pub": "atom", "priv": "atom"
   };
   var typeKeywords = function() {
     var keywords = {"fn": "fn"};
diff --git a/doc/tutorial.md b/doc/tutorial.md
index 37b0b722eaa..f73ddd1b4c4 100644
--- a/doc/tutorial.md
+++ b/doc/tutorial.md
@@ -31,7 +31,7 @@ pleasant high-level features include:
 
 This is an introductory tutorial for the Rust programming language. It
 covers the fundamentals of the language, including the syntax, the
-type system and memory model, and generics.  [Additional
+type system and memory model, generics, and modules. [Additional
 tutorials](#what-next) cover specific language features in greater
 depth.
 
@@ -2113,61 +2113,123 @@ This usage of traits is similar to Java interfaces.
 
 # Modules and crates
 
-The Rust namespace is divided into modules. Each source file starts
-with its own module.
-
-## Local modules
-
-The `mod` keyword can be used to open a new, local module. In the
-example below, `chicken` lives in the module `farm`, so, unless you
-explicitly import it, you must refer to it by its long name,
-`farm::chicken`.
+The Rust namespace is arranged in a hierarchy of modules. Each source
+(.rs) file represents a single module and may in turn contain
+additional modules.
 
 ~~~~
 mod farm {
     pub fn chicken() -> ~str { ~"cluck cluck" }
     pub fn cow() -> ~str { ~"mooo" }
 }
+
 fn main() {
     io::println(farm::chicken());
 }
 ~~~~
 
-Modules can be nested to arbitrary depth.
+The contents of modules can be imported into the current scope
+with the `use` keyword, optionally giving it an alias. `use`
+may appear at the beginning of crates, `mod`s, `fn`s, and other
+blocks.
+
+~~~
+# mod farm { pub fn chicken() { } }
+# fn main() {
+// Bring `chicken` into scope
+use farm::chicken;
+
+fn chicken_farmer() {
+    // The same, but name it `my_chicken`
+    use my_chicken = farm::chicken;
+    ...
+}
+# }
+~~~
+
+These farm animal functions have a new keyword, `pub`, attached to
+them.  This is a visibility modifier that allows item to be accessed
+outside of the module in which they are declared, using `::`, as in
+`farm::chicken`. Items, like `fn`, `struct`, etc. are private by
+default.
+
+Visibility restrictions in Rust exist only at module boundaries. This
+is quite different from most object-oriented languages that also enforce
+restrictions on objects themselves. That's not to say that Rust doesn't
+support encapsulation - both struct fields and methods can be private -
+but it is at the module level, not the class level. Note that fields
+and methods are _public_ by default.
+
+~~~
+mod farm {
+# pub fn make_me_a_farm() -> farm::Farm { farm::Farm { chickens: ~[], cows: ~[], farmer: Human(0) } }
+    pub struct Farm {
+        priv mut chickens: ~[Chicken],
+        priv mut cows: ~[Cow],
+        farmer: Human
+    }
+
+    // Note - visibility modifiers on impls currently have no effect
+    impl Farm {
+        priv fn feed_chickens() { ... }
+        priv fn feed_cows() { ... }
+        fn add_chicken(c: Chicken) { ... }
+    }
+
+    pub fn feed_animals(farm: &Farm) {
+        farm.feed_chickens();
+        farm.feed_cows();
+    }
+}
+
+fn main() {
+     let f = make_me_a_farm();
+     f.add_chicken(make_me_a_chicken());
+     farm::feed_animals(&f);
+     f.farmer.rest();
+}
+# type Chicken = int;
+# type Cow = int;
+# enum Human = int;
+# fn make_me_a_farm() -> farm::Farm { farm::make_me_a_farm() }
+# fn make_me_a_chicken() -> Chicken { 0 }
+# impl Human { fn rest() { } }
+~~~
 
 ## Crates
 
-The unit of independent compilation in Rust is the crate. Libraries
-tend to be packaged as crates, and your own programs may consist of
-one or more crates.
+The unit of independent compilation in Rust is the crate - rustc
+compiles a single crate at a time, from which it produces either a
+library or executable.
 
 When compiling a single `.rs` file, the file acts as the whole crate.
 You can compile it with the `--lib` compiler switch to create a shared
 library, or without, provided that your file contains a `fn main`
 somewhere, to create an executable.
 
-It is also possible to include multiple files in a crate. For this
-purpose, you create a `.rc` crate file, which references any number of
-`.rs` code files. A crate file could look like this:
+Larger crates typically span multiple files and are compiled from
+a crate (.rc) file. Crate files contain their own syntax for loading
+modules from .rs files and typically include metadata about the crate.
 
-~~~~ {.ignore}
+~~~~ { .xfail-test }
 #[link(name = "farm", vers = "2.5", author = "mjh")];
 #[crate_type = "lib"];
+
 mod cow;
 mod chicken;
 mod horse;
 ~~~~
 
 Compiling this file will cause `rustc` to look for files named
-`cow.rs`, `chicken.rs`, `horse.rs` in the same directory as the `.rc`
-file, compile them all together, and, depending on the presence of the
-`crate_type = "lib"` attribute, output a shared library or an executable.
-(If the line `#[crate_type = "lib"];` was omitted, `rustc` would create an
-executable.)
+`cow.rs`, `chicken.rs`, and `horse.rs` in the same directory as the
+`.rc` file, compile them all together, and, based on the presence of
+the `crate_type = "lib"` attribute, output a shared library or an
+executable.  (If the line `#[crate_type = "lib"];` was omitted,
+`rustc` would create an executable.)
 
-The `#[link(...)]` part provides meta information about the module,
-which other crates can use to load the right module. More about that
-later.
+The `#[link(...)]` attribute provides meta information about the
+module, which other crates can use to load the right module. More
+about that later.
 
 To have a nested directory structure for your source files, you can
 nest mods in your `.rc` file:
@@ -2184,56 +2246,65 @@ The compiler will now look for `poultry/chicken.rs` and
 and `poultry::turkey`. You can also provide a `poultry.rs` to add
 content to the `poultry` module itself.
 
-The compiler then builds the crate as a platform-specific shared library or
-executable which can be distributed.
+When compiling .rc files, if rustc finds a .rs file with the same
+name, then that .rs file provides the top-level content of the crate.
 
-## Using other crates
+~~~ {.xfail-test}
+// foo.rc
+#[link(name = "foo", vers="1.0")];
 
-Having compiled a crate that contains the `#[crate_type = "lib"]`
-attribute, you can use it in another crate with a `use`
-directive. We've already seen `extern mod std` in several of the
-examples, which loads in the [standard library][std].
+mod bar;
+~~~
 
-[std]: http://doc.rust-lang.org/doc/std/index/General.html
+~~~ {.xfail-test}
+// foo.rs
+fn main() { bar::baz(); }
+~~~
 
-`use` directives can appear in a crate file, or at the top level of a
-single-file `.rs` crate. They will cause the compiler to search its
-library search path (which you can extend with `-L` switch) for a Rust
-crate library with the right name.
+> ***Note***: The way rustc looks for .rs files to pair with .rc
+> files is a major source of confusion and will change. It's likely
+> that the crate and source file grammars will merge.
 
-It is possible to provide more specific information when using an
-external crate.
+> ***Note***: The way that directory modules are handled will also
+> change. The code for directory modules currently lives in a .rs
+> file with the same name as the directory, _next to_ the directory.
+> A new scheme will make that file live _inside_ the directory.
 
-~~~~ {.ignore}
-extern mod myfarm (name = "farm", vers = "2.7");
-~~~~
+## Using other crates
+
+Having compiled a crate into a library you can use it in another crate
+with an `extern mod` directive. `extern mod` can appear at the top of
+a crate file or at the top of modules. It will cause the compiler to
+look in the library search path (which you can extend with `-L`
+switch) for a compiled Rust library with the right name, then add a
+module with that crate's name into the local scope.
 
-When a comma-separated list of name/value pairs is given after `use`,
-these are matched against the attributes provided in the `link`
+For example, `extern mod std` links the [standard library].
+
+[standard library]: std/index.html
+
+When a comma-separated list of name/value pairs is given after `extern
+mod`, these are matched against the attributes provided in the `link`
 attribute of the crate file, and a crate is only used when the two
 match. A `name` value can be given to override the name used to search
-for the crate. So the above would import the `farm` crate under the
-local name `myfarm`.
+for the crate.
 
 Our example crate declared this set of `link` attributes:
 
-~~~~ {.ignore}
+~~~~ {.xfail-test}
 #[link(name = "farm", vers = "2.5", author = "mjh")];
 ~~~~
 
-The version does not match the one provided in the `use` directive, so
-unless the compiler can find another crate with the right version
-somewhere, it will complain that no matching crate was found.
-
-## The core library
+Which can then be linked with any (or all) of the following:
 
-A set of basic library routines, mostly related to built-in datatypes
-and the task system, are always implicitly linked and included in any
-Rust program.
+~~~~ {.xfail-test}
+extern mod farm;
+extern mod my_farm (name = "farm", vers = "2.5");
+extern mod my_auxiliary_farm (name = "farm", author = "mjh");
+~~~~
 
-This library is documented [here][core].
-
-[core]: core/index.html
+If any of the requested metadata does not match then the crate
+will not be compiled successfully.
 
 ## A minimal example
 
@@ -2246,7 +2317,7 @@ these two files:
 fn explore() -> ~str { ~"world" }
 ~~~~
 
-~~~~ {.ignore}
+~~~~ {.xfail-test}
 // main.rs
 extern mod world;
 fn main() { io::println(~"hello " + world::explore()); }
@@ -2261,113 +2332,33 @@ Now compile and run like this (adjust to your platform if necessary):
 "hello world"
 ~~~~
 
-## Importing
-
-When using identifiers from other modules, it can get tiresome to
-qualify them with the full module path every time (especially when
-that path is several modules deep). Rust allows you to import
-identifiers at the top of a file, module, or block.
-
-~~~~
-extern mod std;
-use io::println;
-fn main() {
-    println(~"that was easy");
-}
-~~~~
-
-
-It is also possible to import just the name of a module (`use
-std::list;`, then use `list::find`), to import all identifiers exported
-by a given module (`use io::*`), or to import a specific set
-of identifiers (`use math::{min, max, pi}`).
-
-Rust uses different namespaces for modules, types, and values.  You
-can also rename an identifier when importing using the `=` operator:
-
-~~~~
-use prnt = io::println;
-~~~~
-
-## Exporting
-
-By default, a module exports everything that it defines. This can be
-restricted with `export` directives at the top of the module or file.
-
-~~~~
-mod enc {
-    export encrypt, decrypt;
-    const SUPER_SECRET_NUMBER: int = 10;
-    fn encrypt(n: int) -> int { n + SUPER_SECRET_NUMBER }
-    fn decrypt(n: int) -> int { n - SUPER_SECRET_NUMBER }
-}
-~~~~
-
-This defines a rock-solid encryption algorithm. Code outside of the
-module can refer to the `enc::encrypt` and `enc::decrypt` identifiers
-just fine, but it does not have access to `enc::super_secret_number`.
-
-## Resolution
-
-The resolution process in Rust simply goes up the chain of contexts,
-looking for the name in each context. Nested functions and modules
-create new contexts inside their parent function or module. A file
-that's part of a bigger crate will have that crate's context as its
-parent context.
-
-Identifiers can shadow each other. In this program, `x` is of type
-`int`:
+Notice that the library produced contains the version in the filename
+as well as an inscrutable string of alphanumerics. These are both
+part of Rust's library versioning scheme. The alphanumerics are
+a hash representing the crate metadata.
 
-~~~~
-type MyType = ~str;
-fn main() {
-    type MyType = int;
-    let x: MyType = 17;
-}
-~~~~
-
-An `use` directive will only import into the namespaces for which
-identifiers are actually found. Consider this example:
-
-~~~~
-mod foo {
-   fn bar() {}
-}
-
-fn main() {
-    let bar = 10;
-
-    {
-        use foo::bar;
-        let quux = bar;
-        assert quux == 10;
-    }
-}
-~~~~
+## The core library
 
-When resolving the type name `bar` in the `quux` definition, the
-resolver will first look at local block context for `baz`. This has an
-import named `bar`, but that's function, not a value, So it continues
-to the `baz` function context and finds a value named `bar` defined
-there.
+The Rust [core] library acts as the language runtime and contains
+required memory management and task scheduling code as well as a
+number of modules necessary for effective usage of the primitive
+types. Methods on [vectors] and [strings], implementations of most
+comparison and math operators, and pervasive types like [`Option`]
+and [`Result`] live in core.
 
-Normally, multiple definitions of the same identifier in a scope are
-disallowed. Local variables defined with `let` are an exception to
-this—multiple `let` directives can redefine the same variable in a
-single scope. When resolving the name of such a variable, the most
-recent definition is used.
+All Rust programs link to the core library and import its contents,
+as if the following were written at the top of the crate.
 
-~~~~
-fn main() {
-    let x = 10;
-    let x = x + 10;
-    assert x == 20;
-}
-~~~~
+~~~ {.xfail-test}
+extern mod core;
+use core::*;
+~~~
 
-This makes it possible to rebind a variable without actually mutating
-it, which is mostly useful for destructuring (which can rebind, but
-not assign).
+[core]: core/index.html
+[vectors]: core/vec.html
+[strings]: core/str.html
+[`Option`]: core/option.html
+[`Result`]: core/result.html
 
 # What next?