2020-12-29 22:43 GMT, Rowan Tommins <rowan.coll...@gmail.com>: > 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 > >
Good breakdown. One benefit of records is that they can be structurally typed (instead of nominally, as classes are), but that's probably never going to happen in PHP. :) Perhaps a `readonly` attribute is best for now? Compare with the annotation supported by Psalm: https://psalm.dev/docs/annotating_code/supported_annotations/#psalm-readonly-and-readonly Olle -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: https://www.php.net/unsub.php