Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Closures

A callable is a closure, short closure, first-class function, bound method, or partial call.

Short closures

A short closure uses fn. This is the preferred closure syntax:

$double = fn(int $value): int {
  return $value * 2;
};

assert!($double(21) == 42);

Like a named function, a short closure may have type parameters, typed parameters, defaults, a return type, attributes, and a block body.

A short closure may also have an expression body:

$factor = 3;
$multiply = fn(int $value): int => $value * $factor;

assert!($multiply(4) == 12);

A block body may contain any statements. It does not return its last expression. Use return to return a value. A block body may declare void; an expression body may not.

A short closure captures each outer variable that its body uses. Capture is by value at creation time. Parameters are not captures.

Explicit captures

A long closure uses function and lists outer variables in use:

$offset = 10;
$add = function(int $value) use ($offset): int {
  return $value + $offset;
};

assert!($add(5) == 15);

Capture copies the current value. A later assignment to the outer variable does not change that copy. Mutating a captured local also does not change the outer local.

Objects keep identity when copied, so a captured object still sees later property changes.

Use a long closure when the explicit capture list helps the reader. Prefer fn otherwise.

$this

A closure or short closure made in an instance method may use $this without listing it in use:

final class Counter {
  public function __construct(private int $value) {}

  public function reader(): fn(): int {
    return fn(): int => $this->value;
  }
}

$counter = new Counter(7);
assert!($counter->reader()() == 7);

The callable keeps the receiver alive.

Callable types

fn(int, string): bool describes a callable by its input and output types. Whim checks callable compatibility when a value crosses a typed boundary, then checks each call as it runs.

Parameter types are contravariant and the return type is covariant. A callable that accepts mixed may replace one that accepts int. A callable that returns int may replace one that returns int|string.

Callable values compare by identity. Two closures with the same source are still different values.