Hi Marco

On Tue, Apr 2, 2024 at 2:56 AM Deleu <deleu...@gmail.com> wrote:
>
>
>
> On Mon, Apr 1, 2024 at 9:20 PM Ilija Tovilo <tovilo.il...@gmail.com> wrote:
>>
>> I'd like to introduce an idea I've played around with for a couple of
>> weeks: Data classes, sometimes called structs in other languages (e.g.
>> Swift and C#).
>>
>> snip
>>
>> Some other things to note about data classes:
>>
>> * Data classes are ordinary classes, and as such may implement
>> interfaces, methods and more. I have not decided whether they should
>> support inheritance.
>
> I'd argue in favor of not including inheritance in the first version. Taking 
> inheritance out is an impossible BC Break. Not introducing it in the first 
> stable release gives users a chance to evaluate whether it's something we 
> will drastically miss.

I would probably agree. I believe the reasoning some languages don't
support inheritance for value types is because they are stored on the
stack. Inheritance encourages large structures, but copying very large
structures over and over on the stack may be slow.

In PHP, objects always live on the heap, and due to CoW we don't have
this problem. Still, it may be beneficial to disallow inheritance
first, and relax this restriction if it is necessary.

>> * Mutating method calls on data classes use a slightly different
>> syntax: `$vector->append!(42)`. All methods mutating `$this` must be
>> marked as `mutating`. The reason for this is twofold: 1. It signals to
>> the caller that the value is modified. 2. It allows `$vector` to be
>> cloned before knowing whether the method `append` is modifying, which
>> hugely reduces implementation complexity in the engine.
>
> I'm not sure if I understood this one. Do you mean that the `!` modifier here 
> (at call-site) is helping the engine clone the variable before even diving 
> into whether `append()` has been tagged as mutating?

Precisely. The issue comes from deeper nested values:

$circle->position->zero();

Imagine that Circle is a data class with a Position, which is also a
data class. Position::zero() is a mutating method that sets the
coordinates to 0:0. For this to work, not only the position needs to
be copied, but also $circle. However, the engine doesn't yet know
ahead of time whether zero() is mutating, and as such needs to perform
a copy.

One idea was to evaluate the left-hand-side of the method call, and
repeat it with a copy if the method is mutating. However, this is not
trivially possible, because opcodes consume their operands. So, for an
expression like `getCircle()->position->zero()`, the return value of
`getCircle()` is already gone. `!` explicitly distinguishes the call
from non-mutating calls, and knows that a copy will be needed.

But as mentioned previously, I think a different syntax offers
additional benefits for readability.

> From outside it looks odd that a clone would happen ahead-of-time while 
> talking about copy-on-write. Would this syntax break for non-mutating methods?

If by break you mean the engine would error, then yes. Only mutating
methods may (and must) be called with the $foo->bar!() syntax.

Ilija

Reply via email to