9.2. Closure calls

Each routine closure defines a routine named 'call' and each iterator closure defines an iterator named 'call!'. These have argument and return types that correspond to the closure type specifiers. Invocations of these features behave like a call on the original routine or iterator with the arguments specified by a combination of the bound values and those provided to 'call' or 'call!'. The arguments to 'call' and 'call!' match the underscores positionally from left to right (e.g. 'i::=bind(2.plus(_)).call(3)' is equivalent to 'i::=2.plus(3)').

Closure types implicitly introduce edges into the type graph. There is an edge from each closure type g to all closure types f that satisfy the contravariant requirement that

  1. f and g have the same name and number of arguments,

  2. f and g either both return a value or neither does,

  3. the mode of each argument is the same (in, out, inout, or once),

  4. contravariant conformance:

For example, 'ROUT{$OB}:INT' is a subtype of 'ROUT{INT}:$OB' and 'ITER{once $OB}' is a subtype of 'ITER{once INT}'.

9.2.1. Closure Examples

Example 9-2. Here we double every element of an array by applying a routine closure 'r' to each element of an array 'a'.

r: ROUT{INT}:INT := bind(2.0.times(_));
loop
   a.set!(r.call(a.elt!))
end

Example 9-3. This illustrates how 'self' may be left unbound. The type of self must be inferredfrom the type context (ROUT{INT}).

r: ROUT{INT} := bind(_.plus(3));
#OUT + r.call(5);           -- prints '8'

Example 9-4. This creates an iterator closure that returns successive odd integers, and then prints the first ten.

odd_ints : ITER{INT}:INT;
odd_ints := bind(1.step!(_,2));
loop
   #OUT + odd_ints.call!(10);
end

Example 9-5. An iterator closure is created that may be used to extract elements of a map that satisfy the selection criteria defined by 'select'.

select:ROUT{T}:BOOL;
select_elt:ITER{FMAP{K,T}}:T;
...
select_elt := bind(_.filter!(select));

Example 9-6. By the conformance rule above, 'ROUT{$OB}:INT' is a subtype of 'ROUT{INT}:$OB'. The ICSI compiler does not yet allow such contravariant closure assignments.

a:ROUT{$OB}:INT;
b:ROUT{INT}:$OB;
b := a;   -- This is a legal assignment
a := b;   -- This is not.