Re: [RFC] [DISCUSSION] Immutable/final/readonly properties

From: Date: Sun, 23 Feb 2020 17:06:13 +0000
Subject: Re: [RFC] [DISCUSSION] Immutable/final/readonly properties
References: 1 2 3 4 5 6 7  Groups: php.internals 
Request: Send a blank email to internals+get-108731@lists.php.net to get a copy of this message
On Sun, Feb 23, 2020, at 2:39 AM, Mike Schinkel wrote: > > On Feb 21, 2020, at 6:17 PM, Larry Garfield <larry@garfieldtech.com> wrote: > > I'm totally on board for better value object support, so that's a good motive > > for me. The question I have is whether this is really a good stepping stone in that direction or if > > it would lead down a wrong path and lock us into too much TIMTOWTDI (for the Perl fans in the room). > > So let's think that through down that path. How would write-once properties lead into > > properly immutable value objects? Or do they give us that themselves? > > > > The biggest challenge for immutable objects, IMO, is evolving them. Eg, > > $result->withContentType(...) to use the PSR-7 example. Would we expect people to do it with a > > method like that, or would there be some other mechanism? If the properties are public, would we > > offer a more syntactic way to modify them directly? > > > > The with*() method style requires cloning the object. What happens to the locked status > > of a set property if the object is cloned? Are they then settable again, or do they come > > pre-locked? > > > > Neither of those seem good, now that I think about it. If they come pre-locked, then you > > really can't clone, change one property, and return the new one (as is the standard practice > > now in that case). If they don't come pre-locked, then the newly created object can have > > everything on it changed, once, which creates a loophole. I'm not sure what the right answer > > is here. > > > > My other concern is a public property (the most likely use case) would have to be set in > > the constructor. If it's not, then callers cannot rely on it having been set yet if it's > > set lazily. And if code inside the class tries to set it lazily, it may already have been set by > > some external code (rightly or wrongly) and cause a failure. > > > > > How do we address that? There's absolutely use cases where setting everything in the > > constructor ahead of time is what you'd do anyway, but there are plenty where you wouldn't > > want to, either, which creates a race condition for who sets it first, or tries to access it before > > it gets set, etc. (This is where my repeated questions about lazy initialization come from.) > > > I have struggled to follow this RFC thread fully, so if I am getting > something out of context, please note that and I apologize in advance. > > However, it would see that rules for write once properties to > support > lazy loading would be rather simple: > > 1. Write-once properties can only be updated once. > 2. Write-once properties can only be updated within the class where > they are declared. This is the common use case I think many envision, but nothing in the proposal requires that. A public write-once property (as currently written) would be world-readable, and world-writeable, once. Separate visibility for internal and external access is a separate matter. (Also potentially useful, but not part of the write-once proposal at the moment.) > 3. If you want to update a property from outside the class, create a > set_<property>() method to allow it to happen. > 4. If you do not want it to be set externally, do not implement a > set_<property>() method. > 5. If you want it to be implemented externally sometimes but not > others, implement guard classes inside the set_<property>() method. > > I think that addresses all scenarios, no? > > -Mike It does not. 1) Race condition if I assume that a public write-once property is a materialized value, but access it before it gets materialized. 2) Race condition if internal non-constructor code wants to set the value, but some external routine has set it first. 3) Cloning creates an interesting and complicated case of both of the above. Does a cloned object start with its write-once bits reset or no? There's problems both ways. Making a write-once property implicitly write-only-from-inside-the-class would help address point 2, but not points 1 or 3. Adding separate get/set visibility modifiers is another interesting idea, but is separate and should be evaluated on its own merits. It is not at this time part of this proposal. --Larry Garfield

« previous php.internals (#108731) next »