On 29/12/2020 18:38, Olle Härstedt wrote:
Instead of shoe-horning everything into the PHP object system, did
anyone consider adding support for records instead, which would always
be immutable, and could support the spread operator for cloning-with
similar as in JavaScript or OCaml? They could be based on PHP arrays
and thus be passed by value.


While we could create a brand new "record" or "struct" type, I think there are a few reasons to think it would end up *looking* more like objects than arrays:

- we have an established syntax for declaring types of object (class Foo {...}), and none for declaring types of array - the 'bar' in $foo['bar'] is an expression, implying dynamic options; the bar in $foo->bar is a bare identifier, implying statically defined options - similarly, we have a syntax for creating object instances, with statically analysable members: new Foo(bar: 42)


The spread operator could be made to work with either style, if we preferred it to using "clone ... with ...":

- ['bar'=>69, ...$existingFoo]
- new Foo(bar: 69, ...$existingFoo)


However, arrays arguably already have a clone-with syntax, more normally thought of as "copy-on-write". Rather than "mutable with special logic to pass and assign by value", I think you can model their behaviour as "immutable with special logic to clone with modifications":

$foo = ['bar'=>42, 'baz'=>101];
$newFoo = $foo; // lazy assignment by value is indistinguishable from assignment by pointer
$newFoo['bar'] = 69; // $newFoo is a modified clone of $foo
$newFoo['bar'] = 72; // mutating $newFoo in place is indistinguishable from creating and assigning another modified clone


In theory, "records" could have this ability with object-like syntax:

$foo = new Foo(bar: 42, baz: 101);
$newFoo = $foo;
$newFoo->bar = 69; // $newFoo is a modified clone
$newFoo->bar = 72; // can be optimised as in-place modification, but conceptually cloning again


In the simple case, that's equivalent to a clone-with:

$foo = new Foo(bar: 42, baz: 101);
$newFoo = clone $foo with { bar: 69 };
$newFoo = clone $newFoo with { bar: 72 }; // can probably be optimised the same way as the above examples


It would allow more complex modifications, though, such as deep modification:

$foo = new Foo(bar: new Bar(name: 'Bob'));
$newFoo = $foo;
$newFoo->bar->name = 'Robert';

That last line would do the same as this:

$newFoo = clone $newFoo with { bar: clone $newFoo->bar with { name: 'Robert' }};

How desirable that is, and how it fits with the use cases in Larry's post, I'm not sure.


Regards,

--
Rowan Tommins
[IMSoP]

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

Reply via email to