2020-07-11 19:08 GMT, Larry Garfield <la...@garfieldtech.com>: > On Sat, Jul 11, 2020, at 9:06 AM, Olle Härstedt wrote: >> Dear internals, >> >> I'd like to discuss the concept of ownership in PHP, from the point of >> view of a new interface UniqueInterface (or SplUniqueInterface or >> something), which will throw a UniqueException if refcount > 1. >> >> Use-case: Mutable objects that cannot be shared (without (deep) cloning). >> >> Rational: Immutable objects are considered "easier to reason about" >> and generally more safe, and as a way to avoid >> spooky-action-at-a-distance. I argue that mutability is totally fine >> as long as it's not *being shared*. Currently, there's no way to >> enforce this in PHP, *but* PHP has a refcounting GC which could do >> this. This would be a more performant alternative than to build lots >> of immutable objects using $obj->whereSomething('bla') constructs. >> >> Cons: If PHP switches to tracing GC, it will be unusable. >> >> What do you think? Should I write it down as an RFC? Implementation >> should be straight-forward, assuming refcount is manipulated at a >> single place in the source. >> >> Regards >> Olle > > I like the goal of addressing shared mutable state is a laudable one and I > think most here share it. However, I think uniqueness checking is the wrong > approach, for reasons others have already explained. > > You're correct that the thing to avoid is shared mutable state. That can be > avoided either by getting rid of mutable state or shared state. Either > would work. (Channeling Kevlin Henny here.) > > In the case of PHP, since we don't have threads to worry about the main > source of shared state is reference variables, or refrence-esque objects. > (Or globals, but I'm assuming most here know to avoid those already.) That > is, mutability or shared-ness within a function is, meh, who cares. It's at > function boundaries that we care. > > As others noted, a ref count check wouldn't help with that much, because the > act of passing an object to another function necessarily increases the > refcount, thus eliminating the main benefit. > > Rather, the way to eliminate shared-ness is to have "structs," that is, > objects that pass by value-ish rather than pass-by-reference-ish. (Yes it's > more complicated than that, I know, I'm talking about the user-space > implications.) PHP 4 objects all worked that way, which was a problem for > anything with services our resources behind it. That's why it changed in > PHP 5 to the more common by-ref-ish behavior, which... is a problem for > value objects. > > Both use cases are valid. It's why newer languages like Go and Rust take a > completely different approach to what "object" even means in the first > place. > > It's been discussed before but never really implemented; I do think the way > to help break the "shared state" side is to allow objects to get flagged as > "will use by-value passing" or "will use by-reference passing" (again, > implications, not implementation). That is, if you have a by-val object and > pass it to a function, it behaves the same way as passing a string or an > array: Copy-on-write of the object when any changes are made to properties > of the object. Probably we'd also need to require that properties of by-val > objects cannot be by-ref objects or resources, which seems reasonable to > me. > > I think that would do a far better job of addressing the > shared-mutable-state issue than reference counting, because it attacks the > root problem rather than a symptom. > > --Larry Garfield > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: https://www.php.net/unsub.php
I think freezing objects might be better fit for my imagined use-case. The only problem I see is that you can't really unfreeze them. Imagine a database connection that only can be open/closed at refcount = 1: ``` $connection = new OwnershipConnection(); $connection->open(); $ps = new PostService($connection); $ps->updateAllPosts(); // Throws exception if $connection->close() $connection->close(); ``` With freeze, you could also do ``` $ps = new PostService($connection->freeze()); ``` to ensure it's not closed by mistake. But then you couldn't close the connection at all, except in __destruct. Especially, CoW for objects (at opt-in) is not a replacement where ownership is supposed to replace immutability for performance reason, e.g. creating a separate immutable database connection for every class that uses it. Immutable builder are already part of PSR, e.g. here: https://www.php-fig.org/psr/psr-7/ I have to wonder how reasonable this is, when freezing or ownership are also relevant solutions, with different trade-offs. Olle -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: https://www.php.net/unsub.php