Skip to content

trpl: Clarify closure terminology #28856

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Oct 8, 2015
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 22 additions & 20 deletions src/doc/trpl/closures.md
Original file line number Diff line number Diff line change
@@ -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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would put the hightlight on the first usage rather than the second, I think, but I can't quite say why

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Totally reasonable, probably better to call out the terminology on the first use.

enclosing scope and are "closed over" when used in the function. From this, we
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these should be single, curly quotes, not double straight quotes

get the name "closures" and Rust provides a really great implementation of
them, as we’ll see.

# Syntax

Expand Down Expand Up @@ -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:

Expand All @@ -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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one space after a period please!

things like documentation and type inference, types within closures are rarely
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Within" means "in the body to me here", so this seems like a regression.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh, I see what you mean there.. maybe it would be better to use one of these?

  • types in the context of closures
  • in the context of closures, types

any thoughts?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are also good, but not quite. Like, the issue is that it's about argument and return types, and not the ones in the body. Hrm.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, makes sense, unfortunately the original has an alternate reading that implies that the issue is around multiple kinds of closures

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about "the full type signatures of closures are rarely documented"?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like it.

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 }
Expand All @@ -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 its enclosing scope in
addition to parameters and local bindings. It looks like this:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one space after a period!


```rust
let num = 5;
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down