**************************************************************************
** title:      Closures
** author:     Brian Frank
** created:    13 Dec 07
** copyright:  Copyright (c) 2007, Brian Frank and Andy Frank
** license:    Licensed under the Academic Free License version 3.0
**************************************************************************

Overview [#overview]
********************
Closures are an expression to create a [function]`Functions` inside
the body of a method.  Closures have the ability to reference local
variables from their enclosing scope.  This ability to create inline
functions which access local scope makes it easy to use closures as
method arguments.  For instance closures are used extensively
as an [iteration]`#iteration` mechanism.

Syntax [#syntax]
****************
The basic syntax of a closure:

  |A a, B b...->R| { stmts }

The start of a closure is its signature which reuses the same
syntax as [function types]`Functions#signatures`.  The body of the
closure is a series of zero or more statements.  The 'return' statement
is used to return a result and exit out of the closure (Fantom doesn't
support any other way to jump out of a closure other than 'return' or
'throw').  Let's look a simple example:

  f := |->| { echo("hi there") }
  f()
  f()

The code above creates a closure that prints a message to the console.
If we run the code above "hi there" is printed twice.  We are assigning
the closure to the variable 'f'.  The closure itself is an expression
which creates an instance of [Func]`sys::Func` - just like '8' is
an expression which creates an [Int]`sys::Int`.  The signature of the
function is '|->|' which means that the function takes no arguments
and returns 'Void'.  Once the closure is assigned to 'f', we can
[call]`Functions#calling` 'f' like any other function.

Here is another example:

  f := |Int a, Int b->Int| { return a + b }
  nine := f(4, 5)

The code above declares a closure which accepts two 'Ints' and
returns their sum.  Notice the closure uses the 'return' statement
to return the result (later we'll see how we can omit it).

Binding Locals [#bindingLocals]
*******************************
The real power of a closure is its ability to bind to the local
variables in its enclosing scope.  Consider this example:

  counter := 0
  f := |->Int| { return ++counter }
  echo(f())
  echo(f())
  echo(f())
  echo(counter)

This example creates a function which returns an 'Int' and then
calls the function three times.  Note how the body of the closure
uses the local variable 'counter'.  The closure has access to both
read and write any variable in its enclosing scope - just like
an 'if' statement or a 'while' loop.  So the output of the code above
is to print "1", "2", "3", and "3".

Scope Lifetime [#scopeLifetime]
===============================
When a closure binds to a local variable in its outer scope,
that variable lives as long as the closure lives.  Remember that
closures are just 'Func' objects which can be passed outside of
the original scope.  Consider this example:

  static Func createFunc()
  {
    counter := 0
    return |->Int| { return ++counter }
  }

  static Void main()
  {
    f := createFunc
    echo(f())
    echo(f())
    echo(f())
  }

The 'createFunc' method returns a closure function bound to the local
variable 'counter'.  The local variable will exist as long as the
closure exists.  In this case the 'main' method assigns the function
to the variable 'f' then calls it three times.  The output will
print "1", "2", and "3".  Effectively this allows closures to store
their own state between invocations.

Binding This [#bindingThis]
===========================
If a closure is declared inside an instance method, then a closure
can bind 'this' variable just like any other local:

  Str first := "Bart"
  Str last  := "Simpson"

  Void test()
  {
    f := |->Str| { return first + " " + this.last }
    echo(f())
  }

The code above illustrates binding to two local slots.  The
closure binds to 'first' with an implicit 'this'.  The closure
uses an explicit 'this' to bind to 'last'.  Note that the 'this'
keyword references the enclosing method's instance, *not* the
the closure object.  This also means generic 'Obj' methods
like 'toStr' and 'type' reference the enclosing method instance,
not the closure instance.

Multiple Closures [#multipleClosures]
=====================================
When a method declares multiple closures, the closures all
share the same local variables:

  counter := 0
  f := |->Int| { return ++counter }
  g := |->Int| { return ++counter }
  echo(f())
  echo(g())
  echo(f())
  echo(g())

The code above prints "1", "2", "3", "4" because both 'f' and 'g'
share the same binding to 'counter'.

Note: in the current implementation all closures share the same
set of locals.  This means that any closure holding a reference to
those locals will prevent garbage collection of all closure
variables.

Closure Parameters [#closureParameters]
***************************************
A closure is just a normal expression and can be passed as an
argument to a method call which expects a 'Func' parameter.
Many key APIs are designed to work with functions.  For example
consider the [List.findAll]`sys::List.findAll` method which
returns a sub-list of every item matching a criteria.  Since we
want to leave the match criteria open ended, 'findAll' lets you
pass in an arbitrary function to determine matches.

Let's consider an example for finding all the even numbers in
a list:

  list := [0, 1, 2, 3, 4]
  f := |Int v->Bool| { return v%2==0 }
  evens := list.findAll(f)

The code above creates a function, then passes it to the 'findAll'
method.  Since the closure is just an expression we could also rewrite
the code as:

  evens := list.findAll(|Int v->Bool| { return v%2==0 })

Since closures are used heavily in this way, Fantom supports a
special syntax borrowed from Ruby.  If a closure is the last
argument to a method call, then the closure can be pulled out as
a suffix to the call:

  evens := list.findAll() |Int v->Bool| { return v%2==0 }

Since we aren't passing any arguments other than the closure we
can simplify this code even further by removing the parens:

  evens := list.findAll |Int v->Bool| { return v%2==0 }

Iteration [#iteration]
**********************
Closures are designed to be the primary mechanism of iteration.
Key methods which accept a function parameter:

  - `sys::List.each`: iterate a list
  - `sys::List.eachr`: reverse iterate a list
  - `sys::Map.each`: iterate a map

When iterating a list both the value and the integer index are
passed to the closure:

  list := ["one", "two", "three"]
  list.each |Str val, Int index| { echo("$index = $val") }

But remember that we don't have to [use all]`Functions#arityCompatibility`
the arguments provided to the function.  For example if we don't
care about the integer index:

  list := ["one", "two", "three"]
  list.each |Str val| { echo(val) }

Map iteration works the same way:

  map := [1:"one", 3:"three", 5:"five"]
  map.each |Str val, Int key| { echo("$key=$val") }
  map.each |Str val| { echo(val) }

Closure Type Inference [#typeInference]
***************************************
Closures which are passed as the last argument to a method support
type inference:

  // fully specified closure signatures
  list := ["one", "two", "three"]
  list.each |Str v, Int i| { echo("$i = $v") }
  list.each |Str v| { echo(v) }

  // inferred closure signatures
  list.each |v, i| { echo("$i = $v") }
  list.each |v| { echo(v) }

If you leave the types off the closures parameters, then they are inferred
based on the closure's context. In the example above a closure passed
to 'Str[].list.each' is inferred to have a type of '|Str,Int|'.

You can also use inference in conjunction with a return type or you
can omit the return type entirely:

  odds = [1, 2, 3, 4, 5].findAll |v->Bool| { v.isOdd }
  odds = [1, 2, 3, 4, 5].findAll |v| { v.isOdd }

Closures can only infer the type when they are being passed to a method
which expects a function.  If a closure's parameters cannot be inferred
then the defaults to 'Obj?':

   // closure with inferred type of |Obj? v|
   f := |v| { echo(v) }

It-Blocks [#itBlocks]
*********************
It-blocks are a special form of closures with the following differences:
  - They omit a function signature and are declared only with curly braces
  - Use [type inference]`#typeInference` based on their context
  - Define an implicit single parameter called 'it'
  - Define an implicit scope for 'it'
  - Return keyword is not allowed in an it-block
  - It-blocks are given compile time permission to set const fields
    on the 'it' parameter, although runtime checks will throw ConstErr
    if an attempt is made to set a const field outside of 'its'
    constructor (see [const fields]`Fields#const`)

An it-block can be used whenever a single parameter function is expected:

  ["a", "b", "c"].each |Str s| { echo(s.upper) }  // long hand
  ["a", "b", "c"].each { echo(it.upper) }         // short hand

In the example above, the it-block is a closure with an implicit 'Str'
parameter called 'it'.

The 'it' parameter works just like the implicit 'this' parameter in
an instance method.  If a given identifier is not declared in the local
scope, then we attempt to bind to 'it':

  ["a", "b", "c"].each { echo(it.upper) }  // explicit it call
  ["a", "b", "c"].each { echo(upper) }     // implicit it call

Just like 'this', if a local variable shadows a slot on 'it', then the
local variable is used.  If an attempt is made to implicitly access a slot
which exists on both 'this' and 'it', then it is a compile time error:

  ["a", "b", "c"].each { echo(toStr) }        // Ambiguous slot error
  ["a", "b", "c"].each { echo(it.toStr) }     // explicit call on it
  ["a", "b", "c"].each { echo(this.toStr) }   // explicit call on this

This Functions [#thisFunc]
**************************
As a general rule the 'sys::This' type is reserved for use only as
the [return type]`Methods#thisReturns` of instance methods.  There is
one exception - you are allowed to declare a method parameter typed
as '|This|' to indicate that an it-block function is expected:

  new make(|This| f) { f(this) }

With-Blocks [#withBlocks]
*************************
Fantom allows you to append an it-block to any expression.  Whenever an
it-block is used and a function is not expected, then the compiler
generates a call to [Obj.with]`sys::Obj.with`:

  list := Str[,].with { fill("x", 3) }   // explicit call to with
  list := Str[,] { fill("x", 3) }        // implicit call to with

The default implementation of 'Obj.with' just applies the function:

  virtual This with(|This| f)
  {
    f(this)
    return this
  }

Using it-blocks and 'Obj.with' allows you open a new lexical scope
with any expression.  It is quite useful for declarative programming.