Skip to content

Commit 636f7d2

Browse files
committed
Suggested revisions to PR 13676.
Most important: distinguish function decl sugar for omitting `-> ()` from type inference on closures. I also tried to add a couple more examples to further emphasize this distinction. Note that this sugar (of omitting `-> ()`) is actually already briefly mentioned in an earlier section, so it is a little tricky deciding whether to put more material here, or to move it up to the previous section. Other drive-by fixes: * Fix the line length of the code blocks to fit in the width provided in the rendered HTML * Some minor revisions to wording (e.g. try to clarify in some cases where a type mismatch is arising).
1 parent f79571f commit 636f7d2

File tree

1 file changed

+53
-28
lines changed

1 file changed

+53
-28
lines changed

src/doc/tutorial.md

+53-28
Original file line numberDiff line numberDiff line change
@@ -1731,13 +1731,13 @@ they try to access `x`:
17311731
let x = 3;
17321732
17331733
// `fun` is an invalid definition
1734-
fn fun () -> () { println!("{}", x) } // cannot capture enclosing scope
1735-
let closure = || -> () { println!("{}", x) }; // can capture enclosing scope
1734+
fn fun () -> () { println!("{}", x) } // cannot capture from enclosing scope
1735+
let closure = || -> () { println!("{}", x) }; // can capture from enclosing scope
17361736
17371737
// `fun_arg` is an invalid definition
1738-
fn fun_arg (arg: int) -> () { println!("{}", arg + x) } // cannot capture enclosing scope
1739-
let closure_arg = |arg: int| -> () { println!("{}", arg + x) }; // can capture enclosing scope
1740-
// ^
1738+
fn fun_arg (arg: int) -> () { println!("{}", arg + x) } // cannot capture
1739+
let closure_arg = |arg: int| -> () { println!("{}", arg + x) }; // can capture
1740+
// ^
17411741
// Requires a type because the implementation needs to know which `+` to use.
17421742
// In the future, the implementation may not need the help.
17431743
@@ -1752,43 +1752,68 @@ Closures begin with the argument list between vertical bars and are followed by
17521752
a single expression. Remember that a block, `{ <expr1>; <expr2>; ... }`, is
17531753
considered a single expression: it evaluates to the result of the last
17541754
expression it contains if that expression is not followed by a semicolon,
1755-
otherwise the block evaluates to `()`.
1755+
otherwise the block evaluates to `()`, the unit value.
17561756
1757-
Since a closure is an expression, the compiler can usually infer the argument and
1758-
return types; so they are often omitted. This is in contrast to a function which
1759-
is a declaration and _not_ an expression. Declarations require the types to be
1760-
specified and carry no inference. Compare:
1757+
In general, return types and all argument types must be specified
1758+
explicitly for function definitions. (As previously mentioned in the
1759+
[Functions section](#functions), omitting the return type from a
1760+
function declaration is synonymous with an explicit declaration of
1761+
return type unit, `()`.)
17611762
17621763
~~~~ {.ignore}
1763-
// `fun` cannot infer the type of `x` so it must be provided because it is a function.
1764-
fn fun (x: int) -> () { println!("{}", x) };
1765-
let closure = |x | -> () { println!("{}", x) };
1764+
fn fun (x: int) { println!("{}", x) } // this is same as saying `-> ()`
1765+
fn square(x: int) -> uint { (x * x) as uint } // other return types are explicit
17661766
1767-
fun(10); // Prints 10
1768-
closure(20); // Prints 20
1769-
1770-
fun("String"); // Error: wrong type
1771-
// Error: This type is different from when `x` was originally evaluated
1772-
closure("String");
1767+
// Error: mismatched types: expected `()` but found `uint`
1768+
fn badfun(x: int) { (x * x) as uint }
17731769
~~~~
17741770
1775-
The null arguments `()` are typically dropped so the end result
1776-
is more compact.
1771+
On the other hand, the compiler can usually infer both the argument
1772+
and return types for a closure expression; therefore they are often
1773+
omitted, since both a human reader and the compiler can deduce the
1774+
types from the immediate context. This is in contrast to function
1775+
declarations, which require types to be specified and are not subject
1776+
to type inference. Compare:
1777+
1778+
~~~~ {.ignore}
1779+
// `fun` as a function declaration cannot infer the type of `x`, so it must be provided
1780+
fn fun (x: int) { println!("{}", x) }
1781+
let closure = |x | { println!("{}", x) }; // infers `x: int`, return type `()`
1782+
1783+
// For closures, omitting a return type is *not* synonymous with `-> ()`
1784+
let add_3 = |y | { 3i + y }; // infers `y: int`, return type `int`.
17771785
1786+
fun(10); // Prints 10
1787+
closure(20); // Prints 20
1788+
closure(add_3(30)); // Prints 33
1789+
1790+
fun("String"); // Error: mismatched types
1791+
1792+
// Error: mismatched types
1793+
// inference already assigned `closure` the type `|int| -> ()`
1794+
closure("String");
17781795
~~~~
1779-
let closure = |x| { println!("{}", x) };
17801796
1781-
closure(20); // Prints 20
1797+
In cases where the compiler needs assistance, the arguments and return
1798+
types may be annotated on closures, using the same notation as shown
1799+
earlier. In the example below, since different types provide an
1800+
implementation for the operator `*`, the argument type for the `x`
1801+
parameter must be explicitly provided.
1802+
1803+
~~~~{.ignore}
1804+
// Error: the type of `x` must be known to be used with `x * x`
1805+
let square = |x | -> uint { (x * x) as uint };
17821806
~~~~
17831807
1784-
Here, in the rare case where the compiler needs assistance,
1785-
the arguments and return types may be annotated.
1808+
In the corrected version, the argument type is explicitly annotated,
1809+
while the return type can still be inferred.
17861810
17871811
~~~~
1788-
let square = |x: int| -> uint { (x * x) as uint };
1812+
let square_explicit = |x: int| -> uint { (x * x) as uint };
1813+
let square_infer = |x: int| { (x * x) as uint };
17891814
1790-
println!("{}", square(20)); // 400
1791-
println!("{}", square(-20)); // 400
1815+
println!("{}", square_explicit(20)); // 400
1816+
println!("{}", square_infer(-20)); // 400
17921817
~~~~
17931818
17941819
There are several forms of closure, each with its own role. The most

0 commit comments

Comments
 (0)