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

Assignment and Indexing

Assignment is an expression. It stores a value and returns that value:

$target = 0;
$result = ($target = 5);

assert!($target == 5);
assert!($result == 5);

Targets

An assignment target may be:

  • a variable;
  • an object property;
  • a static property;
  • a vec or dict index;
  • a vec append target, $values[];
  • a tuple or dict destructuring pattern.

Literals, arithmetic results, strings, and tuple entries are not writable targets. A property on an object returned by a call is writable because the object keeps its identity.

Compound assignment

Whim supports these compound forms:

+=  -=  *=  /=  %=  **=  .=
&=  |=  ^=  <<=  >>=  &&=  ||=  ??=

The target expression runs once:

final class Counter {
  public int $calls = 0;

  public function index(): int {
    $this->calls++;
    return 0;
  }
}

$counter = new Counter();
$values = vec[10];
$values[$counter->index()] += 1;

assert!($counter->calls == 1);
assert!($values[0] == 11);

&&=, ||=, and ??= short-circuit like their non-assignment forms.

??= probes the final property or index and assigns only if it is missing, uninitialized, or null. Every intermediate parent must already exist and have the appropriate type; missing parents throw before the right side runs. No intermediate containers are created. The write obeys the same type, visibility, readonly, and bounds checks as ordinary assignment.

Tuple and vec destructuring

A tuple target accepts a tuple or vec:

($name, $age) = ('Ada', 36);
assert!($name == 'Ada');
assert!($age == 36);

Without a rest target, the source size must match. A trailing rest target collects the remaining values in a vec:

($head, ...$tail) = vec[1, 2, 3];
assert!($head == 1);
assert!($tail == vec[2, 3]);

Use bare ... to allow and ignore the rest.

Defaulted targets

A default runs only when its position is missing. A present null does not use the default:

($name, $role = 'member') = vec['Ada'];
assert!($role == 'member');

($id, $label = 'fallback') = vec[1, null];
assert!($label == null);

A default may use an earlier binding. Once one target has a default, every later fixed target must also have one. A rest target may follow them.

Dict destructuring

A dict target selects named keys:

$source = dict['id' => 7, 'profile' => dict['name' => 'Ada']];
dict['id' => $id, 'profile' => dict['name' => $name]] = $source;

assert!(($id, $name) == (7, 'Ada'));

Each key expression runs before the source expression. A missing key throws. The source must be a dict.

Write order

Whim reads the full source before it writes any target. A target may reuse the source variable without changing later reads:

$values = (1, 2, 3);
($values, $second, $third) = $values;
assert!(($values, $second, $third) == (1, 2, 3));

Whim writes targets from left to right. If one variable appears twice, the last write wins. $_ follows the same rule because it is an ordinary variable.