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