Skip to content

By-reference closure capture does not write back to the session #12

Description

@MarcelloDuarte

A closure that captures by reference mutates a copy, so the change is invisible afterwards:

phunkie > $calls = 0
$calls: Int = 0
phunkie > $bump = function () use (&$calls) { $calls = $calls + 1; return $calls; }
$bump: Callable = <function>
phunkie > $bump()
$var0: Int = 1
phunkie > $calls
$var1: Int = 0        <-- expected Int = 1

The closure sees its own incremented value (it returns 1), but the session variable is untouched. Session variables live in an immutable ImmMap on ReplSession, so there is no storage location for &$calls to alias.

Mutating an object works, because the reference is to the object rather than to the binding:

phunkie > $c = new stdClass(); $c->n = 0
phunkie > $f = function () use ($c) { $c->n = $c->n + 1; }
phunkie > $f(); $c->n
$var2: Int = 1

Reported rather than fixed because the fix is a design question, not a patch: either by-ref capture is genuinely supported (which needs a mutable cell behind session variables, in tension with the immutable session), or it is rejected with a clear message instead of silently doing nothing. Silently discarding the write is the worst of the three.

Found while writing features/repl/php8.5/void_cast.feature, where the scenario had to be rewritten to observe a side effect through an object instead.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions