On Sun, 10 Jan 2021 at 00:33, Larry Garfield <la...@garfieldtech.com> wrote:
> On Sun, Jan 3, 2021, at 11:29 AM, Olle Härstedt wrote: > > > > I'll disagree slightly. A language feature should introduce more > power than > > > it does complexity. Not everything *can* be made absolutely simple, > but the > > > power it offers is worth it. I'd say it should minimize introduced > > > complexity, relative to the power offered. Complexity ideally is > super low, > > > but it's never zero simply by virtue of being "one more thing" that > > > developers need to know how to read. > > > > > > So in this case, we need to compare the power/complexity of asymmetric > > > visibility vs the power/complexity of "immutable... except in these > > > situations." I would argue that asymmetric visibility is more > > > self-documenting, because it states explicitly what those situations > are. > > > > > > The other point is that, as noted, "initonly" creates a gap if you have > > > properties that are inter-dependent. Those then cannot be made > public-read, > > > because that would also mean public-clone-with, and thus allow callers > to > > > violate property relationships. Asymmetric visibility does not have > that > > > problem. > > > > Can you perhaps be a bit more clear on why initonly/readonly would be > > a deal breaker? Seems to me like readonly would cover 80% of > > use-cases? Which is to make data-value objects humane (and fast, since > > you don't need getters anymore) to work with. Seems like you're > > focusing too much on an edge case here. Maybe we should list the > > possibly use-cases? Or at least the main target use-case. > > > > If an object has invariants that need to hold, just throw an exception > > in __clone to force use with withX() instead? Or, as you suggested, > > improve __clone by giving it arguments? > > > > Olle > > It took a few days, but I am back with some more concrete examples. I > decided to try and convert PSR-7 to the various options considered in my > previous post. Here are the results: > > https://peakd.com/hive-168588/@crell/object-properties-part-2-examples > > Along with an analysis of the pros/cons of each. As shown there, > `initonly` creates backdoors that make any but the most basic cases > untennable. > > --Larry Garfield > Thanks for dwelling into this. However, one can already have asymmetric visibility in PHP, just declare a __get() handler. Sure it is slow due to the VM -> User code -> VM jumps but it is possible. Moreover, asymmetric visibility does not prevent mutating an object by calling the constructor once again as follows: $obj->__construct(...$args); This is IMHO the main reason why we want immutability/init only, not to reduce getter methods or wither methods, even if this makes some of them redundant. Also clone-with {} and clone "arguments" could very well be combined by having the props list being passed to the clone-with instruction as a $cloneContext array only available in __clone(), similar to how $http_response_header is populated. [1] The advantages I see in such a construct is that clone-with can handle any type concerns (single/union, enums, literals, typed arrays, generics if/when we get them) for the properties before passing them even to __clone(). If no __clone() handler is defined then it can just assign them but if there needs to be one to handle extra validation, such as the type not being sufficient or a property being dependent on another you are already guaranteed that the property only needs minimal extra validation. As such I still believe immutability and asymmetric visibility are orthogonal features which might be related but fundamentally solve different problems. One is about data integrity, the other is about removing getters/setters. Best regards, George P. Banyard [1] https://www.php.net/manual/en/reserved.variables.httpresponseheader.php