On Fri, Mar 25, 2016 at 11:59 AM, Midori Kocak <mtko...@gmail.com> wrote:

> Hi Everyone,
>
> I think it's better idea to combine those two assignment operator RFC’s.
> So I am going to close the current one and open ??= with ?:=
> What do you think? And we have to find better names.
>
> Wishes,
> Midori Kocak
>

I'd prefer to keep them separate, or at least keep their votes separate.
The ??= operator vote is currently unanimous at 24:0, while the ?:= vote
was closed at something like 9:2, so there clearly are differences of
opinion regarding these two operators.

I'll use this chance for some comments on the proposal. I can see the
general usefulness of ??=, but right now the RFC is severely underspecified
and I'm uncomfortable voting on it in it's current form as so much will
depend on the final implementation. So, what do I mean by underspecified?

The only statement the RFC essentially makes is that $a ??= $b will be the
same as $a = $a ?? $b, for variable-expression $a and expression $b. This
statement, while a good high-level illustration, does not explain the exact
behavior of this operator.

For example, consider the expression $a[print 'X'] ??= $b. A simple
desugaring into $a[print 'X'] = $a[print 'X'] ?? $b will result in 'X'
being printed twice. However, this is not how all other existing compound
assignment operators behave: They will print X only once, as the LHS is
only evaluated once. I assume that ??= would behave the same way.

However, with ??= the problem becomes more complicated. Let us assume that
$a is an ArrayAccess object and consider the expression $a[0] ??= $b. Let
us further assume that $x = $a->offsetGet(0) is non-null. Will $a[0] ??= $b
result in a call to $a->offsetSet(0, $x)? This is what would normally
happen with a compound assignment operator and what would be implied by the
desugaring $a[0] = $a[0] ?? $b. However this assignment is not really
necessary, as we're just reassigning the same value. So, does the call
happen or not? Is the proper desugaring maybe if (!isset($a[0])) $a[0] = $b?

Let us now assume that $a is a recursive ArrayAccess object with
by-reference offsetGet() and consider the expression $a[0][1] ??= expr. For
a normal compound assignment operator, this would issue the call sequence

    $b = expr;
    $x =& $a->offsetGet(0);
    $y = $x->offsetGet(1);
    $y OP= $b;
    $x->offsetSet(1, $y);

Note that we only issue one offsetSet() at the end. We do not refetch $x
via $a->offsetGet(0). How would the same work with the ??= operator? As the
RHS is evaluated lazily, it is my opinion that only performing the
offsetSet() call without refetching $x beforehand would violate PHP's
indirection memory model. Additionally as ??= has to fetch offsets in
BP_VAR_IS mode, we likely wouldn't be able to write them without refetching
anymore.

So, what would be the desugared call sequence for $a[0][1] ??= expr?
Something like this?

    if (!$a->offsetHas(0)) {
        goto assign;
    }
    $x = $a->offsetGet(0);
    if (x === null) {
        goto assign;
    }
    if (!$x->offsetHas(0)) {
        goto assign;
    }
    $y = $x->offsetGet(0);
    if ($y === null) {
        goto assign;
    }
    goto done;
assign:
    $b = expr;
    $x =& $a->offsetGet(0);
    $x->offsetSet(1, $b);
done:

That would be some first thoughts on the issue, though I'm sure there are
more subtleties involved. I'd like to see the exact behavior of ??= (and
?:=) specified.

I'm also pretty sure that writing a patch for this will not be entirely
easy. The combination of execute-once LHS side-effects and lazy RHS
execution does not translate well to PHP's VM constraints.

Regards,
Nikita

Reply via email to