From 8e420e07d914a50ef279de60e6b3d303e82bfd72 Mon Sep 17 00:00:00 2001 From: Craig Hills Date: Mon, 5 Oct 2015 22:25:19 -0400 Subject: [PATCH 1/3] trpl: Clarify closure terminology This is to address issue #28803 --- src/doc/trpl/closures.md | 42 +++++++++++++++++++++------------------- src/llvm | 2 +- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/doc/trpl/closures.md b/src/doc/trpl/closures.md index 983af4a0efe7f..85e74b083b417 100644 --- a/src/doc/trpl/closures.md +++ b/src/doc/trpl/closures.md @@ -1,9 +1,10 @@ % Closures -Rust not only has named functions, but anonymous functions as well. Anonymous -functions that have an associated environment are called ‘closures’, because they -close over an environment. Rust has a really great implementation of them, as -we’ll see. +Sometimes it is useful to wrap up a function and free variables for better +clarity and reuse. The _free variables_ that can be used come from the +enclosing scope and are "closed over" when used in the function. From this, we +get the name "closures" and Rust provides a really great implementation of +them, as we’ll see. # Syntax @@ -34,7 +35,7 @@ assert_eq!(4, plus_two(2)); ``` You’ll notice a few things about closures that are a bit different from regular -functions defined with `fn`. The first is that we did not need to +named functions defined with `fn`. The first is that we did not need to annotate the types of arguments the closure takes or the values it returns. We can: @@ -44,14 +45,14 @@ let plus_one = |x: i32| -> i32 { x + 1 }; assert_eq!(2, plus_one(1)); ``` -But we don’t have to. Why is this? Basically, it was chosen for ergonomic reasons. -While specifying the full type for named functions is helpful with things like -documentation and type inference, the types of closures are rarely documented -since they’re anonymous, and they don’t cause the kinds of error-at-a-distance -problems that inferring named function types can. +But we don’t have to. Why is this? Basically, it was chosen for ergonomic +reasons. While specifying the full type for named functions is helpful with +things like documentation and type inference, types within closures are rarely +documented since they’re anonymous, and they don’t cause the kinds of +error-at-a-distance problems that inferring named function types can. -The second is that the syntax is similar, but a bit different. I’ve added spaces -here for easier comparison: +The second is that the syntax is similar, but a bit different. I’ve added +spaces here for easier comparison: ```rust fn plus_one_v1 (x: i32) -> i32 { x + 1 } @@ -63,8 +64,8 @@ Small differences, but they’re similar. # Closures and their environment -Closures are called such because they ‘close over their environment’. It -looks like this: +The environment for a closure can include bindings from it's enclosing scope in +addition to parameters and local bindings. It looks like this: ```rust let num = 5; @@ -197,9 +198,10 @@ frame. Without `move`, a closure may be tied to the stack frame that created it, while a `move` closure is self-contained. This means that you cannot generally return a non-`move` closure from a function, for example. -But before we talk about taking and returning closures, we should talk some more -about the way that closures are implemented. As a systems language, Rust gives -you tons of control over what your code does, and closures are no different. +But before we talk about taking and returning closures, we should talk some +more about the way that closures are implemented. As a systems language, Rust +gives you tons of control over what your code does, and closures are no +different. # Closure implementation @@ -288,9 +290,9 @@ isn’t interesting. The next part is: # some_closure(1) } ``` -Because `Fn` is a trait, we can bound our generic with it. In this case, our closure -takes a `i32` as an argument and returns an `i32`, and so the generic bound we use -is `Fn(i32) -> i32`. +Because `Fn` is a trait, we can bound our generic with it. In this case, our +closure takes a `i32` as an argument and returns an `i32`, and so the generic +bound we use is `Fn(i32) -> i32`. There’s one other key point here: because we’re bounding a generic with a trait, this will get monomorphized, and therefore, we’ll be doing static diff --git a/src/llvm b/src/llvm index 62ad301a2407a..2e9f0d21fe321 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit 62ad301a2407a7aca50c1d5120c63597d676d29f +Subproject commit 2e9f0d21fe321849a4759a01fc28eae82ef196d6 From a78a874ebb8c3348f2e1cb7a687636ab26a85a1c Mon Sep 17 00:00:00 2001 From: Craig Hills Date: Mon, 5 Oct 2015 22:32:53 -0400 Subject: [PATCH 2/3] possessive its --- src/doc/trpl/closures.md | 2 +- src/llvm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/trpl/closures.md b/src/doc/trpl/closures.md index 85e74b083b417..fee18cb016791 100644 --- a/src/doc/trpl/closures.md +++ b/src/doc/trpl/closures.md @@ -64,7 +64,7 @@ Small differences, but they’re similar. # Closures and their environment -The environment for a closure can include bindings from it's enclosing scope in +The environment for a closure can include bindings from its enclosing scope in addition to parameters and local bindings. It looks like this: ```rust diff --git a/src/llvm b/src/llvm index 2e9f0d21fe321..62ad301a2407a 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit 2e9f0d21fe321849a4759a01fc28eae82ef196d6 +Subproject commit 62ad301a2407a7aca50c1d5120c63597d676d29f From 7895ec2d5752c5a5dacd17d463e401d9e85fac13 Mon Sep 17 00:00:00 2001 From: Craig Hills Date: Tue, 6 Oct 2015 10:30:33 -0400 Subject: [PATCH 3/3] address review concerns --- src/doc/trpl/closures.md | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/doc/trpl/closures.md b/src/doc/trpl/closures.md index fee18cb016791..7d4452a4c8470 100644 --- a/src/doc/trpl/closures.md +++ b/src/doc/trpl/closures.md @@ -1,9 +1,9 @@ % Closures -Sometimes it is useful to wrap up a function and free variables for better -clarity and reuse. The _free variables_ that can be used come from the -enclosing scope and are "closed over" when used in the function. From this, we -get the name "closures" and Rust provides a really great implementation of +Sometimes it is useful to wrap up a function and _free variables_ for better +clarity and reuse. The free variables that can be used come from the +enclosing scope and are ‘closed over’ when used in the function. From this, we +get the name ‘closures’ and Rust provides a really great implementation of them, as we’ll see. # Syntax @@ -46,10 +46,11 @@ assert_eq!(2, plus_one(1)); ``` But we don’t have to. Why is this? Basically, it was chosen for ergonomic -reasons. While specifying the full type for named functions is helpful with -things like documentation and type inference, types within closures are rarely -documented since they’re anonymous, and they don’t cause the kinds of -error-at-a-distance problems that inferring named function types can. +reasons. While specifying the full type for named functions is helpful with +things like documentation and type inference, the full type signatures of +closures are rarely documented since they’re anonymous, and they don’t cause +the kinds of error-at-a-distance problems that inferring named function types +can. The second is that the syntax is similar, but a bit different. I’ve added spaces here for easier comparison: @@ -65,7 +66,7 @@ Small differences, but they’re similar. # Closures and their environment The environment for a closure can include bindings from its enclosing scope in -addition to parameters and local bindings. It looks like this: +addition to parameters and local bindings. It looks like this: ```rust let num = 5; @@ -454,7 +455,7 @@ autogenerated name. The error also points out that the return type is expected to be a reference, but what we are trying to return is not. Further, we cannot directly assign a `'static` lifetime to an object. So we'll take a different approach and return -a "trait object" by `Box`ing up the `Fn`. This _almost_ works: +a ‘trait object’ by `Box`ing up the `Fn`. This _almost_ works: ```rust,ignore fn factory() -> Box i32> {