> On Jun 5, 2021, at 12:51 PM, Larry Garfield <la...@garfieldtech.com> wrote: > > On Fri, Jun 4, 2021, at 10:19 AM, Nikita Popov wrote: >> Hi internals, >> >> I'd like to open the discussion on readonly properties: >> https://wiki.php.net/rfc/readonly_properties_v2 >> >> This proposal is similar to the >> https://wiki.php.net/rfc/write_once_properties RFC that has been declined >> previously. One significant difference is that the new RFC limits the scope >> of initializing assignments. I think a key mistake of the previous RFC was >> the confusing "write-once" framing, which is both technically correct and >> quite irrelevant. >> >> Please see the rationale section ( >> https://wiki.php.net/rfc/readonly_properties_v2#rationale) for how this >> proposal relates to other RFCs and alternatives. >> >> Regards, >> Nikita > > Thank you for the detailed analysis in the rationale section. I am, however, > still skeptical of this approach, for a couple of reasons. > > 1. This does appear to address the "leakage" problem I noted in my earlier > analysis around the start of the year, when considering the writeonce > proposal[1][2]. That's great to see. > > 2. It doesn't address the larger question of cloning, however. The answer > for now seems "maybe we'll get clone-with at some point", which would be a > way around it, but there is no active RFC for that right now. I'm obviously > very in favor of RFCs that complement each other to give more than the sum of > their parts, but those RFCs need to be at least on the horizon to actually > come together. Right now that looks like it won't happen this cycle. Absent > clone-with, readonly would be effectively unusable in any evolvable object of > any non-trivial complexity. It also wouldn't work with objects that need > properties that are not constructor arguments, such as PSR-7 type objects. > That's a no in my book.
Larry, To address the cloning objection to raise to Nikita's RFC there is one solution you did not mention in your blog post[1. Rather than your clone-with using a syntax that does not exist anywhere else[2] in PHP we could instead use one similar to your preferred "clone-with" approach where a closure could be run in an internal context. This closure would give the best of both your clone-with and of __clone() approaches. Applying this approach to your example in [3] gives us: $r6 = clone $r5 with function($obj) { $obj->uri = new Uri('https://python.org/'); $obj->headers = ['host' => 'http://java.com/']; $obj->version = 'the old one'; }; If PHP Internals were to approve the "Auto-capturing multi-statement closures" RFC[4] we could also have auto-capture in a place where it would be likely common: $uri = new Uri('https://python.org/'); $headers = [host => 'http://java.com/']; $version = 'the old one'; $r6 = clone $r5 with fn($obj) { $obj->uri = $uri; $obj->headers = $headers; $obj->version = $version; }; Another improvement, which I don't know if it is possible or even advisable, is if the closure could have automatic access to a $this variable for the instance of the cloned object then it becomes even simpler: $uri = new Uri('https://python.org/'); $headers = [host: 'http://java.com/']; $version = 'the old one'; $r6 = clone $r5 with fn() { $this->uri = $uri; $this->headers = $headers; $this->version = $version; }; Interestingly, using your example[2] again, if we were to adopt the same syntax for `new` statements we could obviate the need for tedious and verbose "wither" methods as well as the numerous internal clones and throwaway variables needed with withers called immediately after instantiation. For example: $r2 = new Request() with fn() { $this->method = 'POST'; $this->uri = new Uri('https://php.net/'); $this->protocolVersion = '2.0'; $this->header = [ 'cache' => 'none' ]; }; Lastly, you proposed "with" as your keyword to identify the initialization values which I assume you picked it because of the "wither" method pattern, and my examples above followed suit. However, given `with` is not currently a reserved word in PHP and using a closure inherently provides an existing keyword, PHP could leverage `function` and/or `fn` to indicate "with." (Note the following example do not include the two (2) enhancements mentioned above using fn and $this): $r6 = clone $r5 function($obj) {...}; -Mike [1] https://peakd.com/hive-168588/@crell/object-properties-and-immutability <https://peakd.com/hive-168588/@crell/object-properties-and-immutability> [2] Even though I would very much like to see that syntax become a general purpose syntax for object instantiation, I think it would not be good to use it unless it were fully fleshed out for much greater utility. [3] https://peakd.com/hive-168588/@crell/object-properties-part-2-examples <https://peakd.com/hive-168588/@crell/object-properties-part-2-examples> [4] https://wiki.php.net/rfc/auto-capture-closure <https://wiki.php.net/rfc/auto-capture-closure>