Hey Everyone,

Thank you for the lot of feedback! Sorry, I'm going to have to answer in a
single email otherwise I would have to send too many emails.

Alexandru wrote:

 How about just allowing a block of code after the clone statement that
> would execute it in the same context as the clone context, allowing to
> modify once readonly variables.
> Allows better flexibility compared with clone with syntax or clone method:


 This is an interesting alternative, but as Tim pointed out in a later
reply, the block would run in the private scope, which is contrary to my
intentions (and what I consider
the best solution).

Michał wrote:

I am curious if possible to implement the feature without using `with`
> keyword
> it visually could look pretty close to something like an object
> initializer in the future:
> return clone $this {c: 1};
> return new Bar {c: 1};


That's exactly what I tried first, but unfortunately, this syntax led to
parser ambiguities, so at last I had to settle on using "with".

Rowan wrote:

1) You mention in the Alternatives sometimes needing access to the
> original instance; it would be good to have an example of how this looks
> with the clone-with syntax.


Makes sense, so I've just come up with an example where a linked list of
objects are created. Let me know if you have a better example :)

2) How does this interact with an __clone() method? I'm guessing the
> __clone() would be called first, and then the with-clause applied?


Yeah, thanks for pointing this out! I agree that the clarification is very
much needed. BTW the evaluation order
is exactly how you wrote. This is now added to the RFC.

Tim wrote:

> In which order will __clone(), foo(), bar(), quux(), baz() be evaluated
> and what will happen if one of them throws an Exception? Will
> destructors of the cloned object run? When?


In fact, after the initial ZEND_CLONE opcode (which possibly invokes
__clone()), a separate opcode is generated for each
assignment (the newly added ZEND_CLONE_INIT_PROP). This means that foo(),
bar(), quux(), and baz() will be evaluated
in this very order. If any of them throws an exception, evaluation stops
and the assignments are not rolled back.

Regarding the destructors: yes, the destructor of the cloned object runs
immediately. In order to make sure, I've just added a test case:
https://github.com/php/php-src/pull/9497/commits/4d184f960ac1b5590d87739ee3278c13fac157de
I hope that this result is what
you expect.

Michal wrote:

> Just noticed the "Property name expressions" and am wondering if it could
> be a separate feature
> allowing for passing named arguments to functions/constructors in the same
> fashion?


As far as I can see, Nikita didn't propose the expression1() =>
expression2() syntax in the named params RFC due to
the same ambiguity I mentioned in the RFC (identifier vs. global constant).
But I don't think this is set in stone, however,
I do think that some optimizations would have to be disabled when param
names weren't evaluatable in
compile-time (https://github.com/php/php-src/pull/10831).

Andreas wrote:

What about argument unpacking?
> I don't know if we can combine this with ":" syntax or only with "=>".


For now, argument unpacking (property unpacking?) is not possible. But it
is definitely something that could be added in the future.

Tim wrote:

I'd rather see only the fat-arrow being allowed. Unless I'm missing
> something, braces with colon is not used anywhere else, whereas braces +
> '=>' is known from match() and '=>' more generally is already used with
> array literals [1]. Having two similar syntaxes for the same thing is
> not great when both are commonly needed is not great. They need to be
> documented and learned by developers.


I can only repeat what Rowan answered, since I agree with it completely:

I think it makes sense to have an unquoted form here, because the common
> case is that they are names which analysers can match statically to
> particular properties, not strings which will be analysed at runtime. There
> are plenty of places in the language where dynamic names are allowed, but
> we don't just use strings for the static case


However, I'm not completely sold on making "clone with" look like a
function call (return clone $this with (a: 1);), but
at least I like it more than using an array-like style (return clone $this
with [a: 1];). My intention with
using curly brackets (return clone $this with {a: 1};) is to highlight the
fact that it is a map
of key-value pairs, similarly how the JSON standard does so. Not to mention
that "clone with" serves a very
similar purpose to object initializers, and the different languages I know
to have this feature use
a similar syntax (Java: http://wiki.c2.com/?DoubleBraceInitialization, C#:
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/object-and-collection-initializers#object-initializers
).

Regards,
Máté

Reply via email to