On Tue, 13 Jun 2023 at 22:13, Larry Garfield <la...@garfieldtech.com> wrote:
>
> On Tue, Jun 13, 2023, at 3:51 PM, Máté Kocsis wrote:
> > Hi Larry,
> >
> > In this case, if the `with` happens first, then the new address object is
> >> cloned needlessly, but that *probably* doesn't hurt anything.  But $newAddr
> >> !== $p3->address.
> >>
> >
> > Yes, I agree with this: "clone $this with ["x" => "y"];" is the easiest to
> > mentally model as a shorthand for "$self = clone $this; $self->x = "y";".
> > If we agree with this model, then it would be weird to execute __clone() at
> > the end indeed. But I think Nicolas' example explained this fact much
> > better than I could. :) Also, separating __clone() from the rest of the
> > clone opcode would be .
> >
> > And you are right, some objects may be cloned unnecessarily, which doesn't
> > hurt, but isn't ideal for sure. I should mention that in ideal
> > circumstances (when all properties are readonly + all of them are
> > initialized during construction + none of them are mutable internally),
> > deep cloning is not 100% required, unless only for defensive programming
> > purposes.
> >
> > Regards,
> > Máté
>
> Where all properties are readonly, and if an object those are *also* 
> readonly, and all are assigned in the constructor...
>
> Yeah, that ideal case is kinda narrow, and likely will remain so for a long 
> while yet.
>
> Whichever order it goes in, that should be documented explicitly and the 
> reasoning for it included.  (Feel free to pilfer my examples above 
> extensively if that helps.)
>
> As for the syntax itself, my preferences, in order, would be:
>
> 1. clone $foo with (...), where (...) follows named-argument syntax in all 
> its variants and forms, which includes ...$arr.
>
> 2. clone $foo with $array, where $array is an honest to goodness assoc 
> array/array literal, created by any means the developer wants.
>
> Either of those are equally expressive; the first is, IMO, cleaner and easier 
> to read/type, and probably nicer on static analysis tools, but they're still 
> both equally expressive.
>
> Anything less than that is, IMO, creating unnecessary confusion about how the 
> syntax behaves that will trip up developers left and right.
>
> --Larry Garfield

Hello list,
First, I am very much in favor of the named-argument syntax `clone
$obj with (key: $value, ...)`, with support for argument unpacking.

The syntax is well suited for the most common case, which is regular
wither methods for one or more known properties.
I don't like the array syntax as a default. It has inferior DX for
regular withers, and possible performance impact from the temporary
array.

For the execution scope ideas:
I kind of like the idea to have a special object state or scope effect
where some properties are writable that otherwise wouldn't be.
However, I don't like this kind of concept being introduced as a
special case only for this clone execution scope.
E.g. the current "readonly" implementations actually means write-once
+ write-private, applied on property level. But in the clone scope it
would mean something different.

I have one question though:
What could be the best way to modify readonly properties from a parent class?
Obviously we can call a parent wither. But this means we now have two
clone operations, which can have a performance impact.

class C extends B {
  private readonly $isGreyscale;
  function withColor($color): static {
    // One clone operation in B, another in C.
    return = clone parent::withColor($color) with (
      // Ok it's a bit silly to make this a separate property.
      isGreyscale: $color->isGreyscale(),
    );
  }
}

The same problem also occurs if the parent readonly property is public.
We must call the parent wither, otherwise we have no permission to
update the property.

One workaround is to redeclare the property in the child class.
https://3v4l.org/Rn1CR

I think the solutions/workarounds in both cases are acceptable,
assuming that the parent wither call is rare enough.

There could even be a future compiler optimization where "clone foo()"
will immediately garbage-collect the temporary object, and re-use the
memory space for the clone. I don't know enough about php internals to
know if that would work.

--- Andreas

>
> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: https://www.php.net/unsub.php
>

Reply via email to