Skip to content

Commit

Permalink
Give more explanation when introducing closures
Browse files Browse the repository at this point in the history
  • Loading branch information
mdinger committed Apr 19, 2014
1 parent ad0cdd7 commit b580964
Showing 1 changed file with 29 additions and 7 deletions.
36 changes: 29 additions & 7 deletions src/doc/tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -1719,19 +1719,41 @@ environment). For example, you couldn't write the following:
~~~~ {.ignore}
let foo = 10;
fn bar() -> int {
return foo; // `bar` cannot refer to `foo`
}
// `bar` cannot refer to `foo`
fn bar() -> () { println!("{}", foo); }

This comment has been minimized.

Copy link
@eddyb

eddyb Apr 21, 2014

Is -> () used in the tutorial? It sure isn't idiomatic.

This comment has been minimized.

Copy link
@mdinger

mdinger Apr 21, 2014

Author Owner

-> () wasn't used. Maybe -> || would be better...I don't know.

This comment has been minimized.

Copy link
@eddyb

eddyb Apr 21, 2014

Just don't return anything, -> () is a redundant way of saying that.

This comment has been minimized.

Copy link
@mdinger

mdinger Apr 21, 2014

Author Owner

Okay. They mention it here briefly before stating the shorter way. You don't object to it in this position do you?

To me, the issue is that a closure is supposed to look syntactically similar to a function but I had no way of knowing that. I thought it looked syntactically similar to an int instantiation. So be explicit so the uninformed can understand easier.

It's completely fine to revert to compact after it is explained. Return something is also an option but I thought simpler equations are easier to understand.

~~~~
Rust also supports _closures_, functions that can access variables in
the enclosing scope.
the enclosing scope. Compare `foo` in these:
~~~~
fn bar() -> () { println!("{}", foo) }; // cannot reach enclosing scope
let closure = |foo| -> () { println!("{}", foo) }; // can reach enclosing scope

This comment has been minimized.

Copy link
@zolrath

zolrath Apr 19, 2014

It seems like making your closure capture an external variable here would show how the closure works more clearly?

let x = 3;

fn  bar       (foo: int) -> () { println!("{}", foo + x) }; // Cannot capture enclosing scope
let closure = |foo: int| -> () { println!("{}", foo + x) }; // Can capture enclosing scope

closure(4);  // Prints: 7
bar(4);      // Will not compile.

This comment has been minimized.

Copy link
@pnkfelix

pnkfelix Apr 19, 2014

(Of course, to be clear, the comment should indicate that the thing that doesn't compile is the definition of bar, not the call to it.)

This comment has been minimized.

Copy link
@mdinger

mdinger Apr 19, 2014

Author Owner

I'm glad you pointed that out because I couldn't see how to do that before. I tried to call x like you did but it wouldn't compile. I didn't think it could be done. I thought it required static.

Simplified it. Simple is good.

let x = 3;

// `bar` is an invalid definition
fn  bar       () -> () { println!("{}", x) }; // Cannot capture enclosing scope
let closure = || -> () { println!("{}", x) }; // Can capture enclosing scope

closure();  // Prints: 3
bar();      // Still won't work

This comment has been minimized.

Copy link
@eddyb

eddyb Apr 21, 2014

Well, it's a closure because it closes over some captures.
I know I'm late, but foo in the original example isn't part of the enclosing scope, but an argument.
Regular functions can have an argument just like the closure example did.

This comment has been minimized.

Copy link
@mdinger

mdinger Apr 21, 2014

Author Owner

Yeah, I see that now. See d67b1b2 where I try to contrast them directly.

For reference, these are the type of things I wondered while trying to understand the part below:

  • Why is a constructor was being called on an int b (b(10))?
  • Why is the absolute value of arg multiplied by println!(...) and why does it result in a closure?
  • Why is the times sign (*) missing from arg times println!(...)?
  • What does a closure specifically mean?
  • Which part does closure actually refer to?
  • How is a closure similar to a function?
  • Why does closure syntax completely ignore function rules ?
fn call_closure_with_ten(b: |int|) { b(10); }

let captured_var = 20;
let closure = |arg| println!("captured_var={}, arg={}", captured_var, arg);

call_closure_with_ten(closure);
~~~~
Closures can be utilized in this fashion:
~~~~
fn call_closure_with_ten(b: |int|) { b(10); }
// Create a nameless function and assign it to `closure`.
// It's sole argument is a yet unknown `foo` to be supplied
// by the caller.
let closure = |foo| -> () { println!("{}", foo) };
// Define `call_closure_with_ten` to take one argument and return null `()`.
// `fun` is a function which takes one `int` argument `|int|` and also returns
// null `()`. `|int|` defines the `fun` to be of type _closure_
fn call_closure_with_ten(fun: |int| -> ()) -> () { fun(10); }
let captured_var = 20;
let closure = |arg| println!("captured_var={}, arg={}", captured_var, arg);
// The caller supplies `10` to the closure
// which prints out the value
call_closure_with_ten(closure);
~~~~
This can be simplified by removing null arguments:
~~~~
let closure = |foo| println!("{}", foo);
fn call_closure_with_ten(fun: |int|) { fun(10); }
call_closure_with_ten(closure);
~~~~
Expand Down

0 comments on commit b580964

Please sign in to comment.