On Sat, Jan 9, 2021, at 7:24 PM, G. P. B. wrote:
> On Sun, 10 Jan 2021 at 00:33, Larry Garfield <la...@garfieldtech.com> wrote:

> > 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.

Many things are technically possible, but only in lame ways.  The __get() 
callback is one such lame way of doing many things.  The existence of a lame 
workaround for something hasn't stopped us from improving the developer 
experience of the language before nor should it now.

> Moreover, asymmetric visibility does not prevent mutating an object by
> calling the constructor once again as follows:
> $obj->__construct(...$args);

I agree with Rowan's point here.  This is a bug in the language.  I've never 
actually seen that bug exploited in the wild, but the answer here is to fix 
that bug, not to use it as justification to not improve the language.

> 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.

The "main reason" for immutability depends on who you ask. :-)  My original 
post laid out some of the main arguments I've seen.  Which one is the "main 
reason" is subjective and I don't think there's any clear consensus on it.  
Fortunately, if we do it right we can all get what we want out of it and it 
doesn't matter which benefit was more important in hindsight.

> 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.

That would entail assigning the properties first, then allowing __clone() to 
override if desired, if I understand you correctly.  That means the object is 
in an invalid state at least for a time.  I'm not wild about that.  It would 
also change the logic of when __clone() happens, which right now is immediately 
after the object is duplicated.  What you're suggesting is changing it to:

* Duplicate object
* Assign with'ed properties
* Call __clone(), which could throw

To be fair, I didn't consider where the with'ed properties would be assigned 
relative to __clone() in my writeup.  (I should perhaps have done so.)

But that still doesn't resolve the issue of all the validation being shoved 
into one big method.  It only removes the "just assign it blindly" default 
case.  All of the other validation is still needed, and still just as fugly.

> 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.

Disagree.  Asymmetric visibility achieves nearly all the same end results as 
initonly, but without introducing data integrity problems or fugly hacks 
(__clone()) to resolve them.  The main takeaway from my experimentation, as I 
see it, is that initonly offers very little *in practice* in the way of data 
integrity guarantees beyond what asymmetric visibility does.  Only in the 
trivial case where a property is fully validated by the type system 
automatically and has no inter-dependencies does it have any benefit.  And the 
benefit is, actually, only moving the `clone with` statement from inside a 
single-expression method (which I'm hoping to make simpler, as noted) to the 
calling code.  I'm not sure that's always a net win.

--Larry Garfield

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php

Reply via email to