Well crap I just realised I hadn’t hit reply-all several replies ago!. I also just noticed that you had mentioned about allowing property writes only in __construct and __clone last week, and asked about how it might look. I wasn’t subscribed then so I didn’t see the earlier discussions.
I’ll go back and read through the earlier discussions, I don’t want to rehash what’s already been suggested and discarded due to impracticality. > On 7 Sep 2016, at 19:04, Stephen Reay <php-li...@koalephant.com> wrote: > > Right, but thats just because ($object) is a statement that evaluates to > $object and clone is a language construct, isn’t it? I don’t think I’ve ever > seen clone($object) used in the wild. > > What do you think about having the change assignment(s) be handled by > __clone() (perhaps with a $changes array as its argument?), so the developer > still has control over how/what things are set, as they do in __construct. > I fear that having the properties set by the clone operation is one step too > much into the ‘it happens by magic’ direction - PHP doesn't auto-set > properties passed to a constructor, so why here? > > > >> On 7 Sep 2016, at 18:50, Silvio Marijić <marijic.sil...@gmail.com >> <mailto:marijic.sil...@gmail.com>> wrote: >> >> Well it's not new, both clone $object and clone($object) are valid >> statements in PHP at the moment. But yes, you are close, in my opinion >> constructor and clone are the points where object can be modified. >> Syntax can be discussed. But we should try to have minimal impact as >> possible on the syntax. >> >> 2016-09-07 13:37 GMT+02:00 Stephen Reay <php-li...@koalephant.com >> <mailto:php-li...@koalephant.com>>: >> OK. I could live with a concept where the object is only modifiable as part >> of the clone operation, but Im not mad about that syntax. >> >> Are you proposing that clone($object, array $changes) is a new builtin >> function/language construct, and it does the actual property writes? In this >> situation, would it be safe to say that only the constructor (and >> destructor? e.g. imagine closing a resource handle in a destructor) can make >> changes to class properties? >> >> Could that be achieved with syntax closer to what we use now? `clone $this >> use ($foo, $bar, $baz);` or similar? >> >> >> >>> On 7 Sep 2016, at 18:19, Silvio Marijić <marijic.sil...@gmail.com >>> <mailto:marijic.sil...@gmail.com>> wrote: >>> >>> I've forgot return in addItem() but you get the idea >>> >>> 2016-09-07 13:19 GMT+02:00 Silvio Marijić <marijic.sil...@gmail.com >>> <mailto:marijic.sil...@gmail.com>>: >>> Hi Stephen, >>> >>> Well in your example it would look like this: >>> >>> immutable class ValueObject { >>> public $values = []; >>> public function __construct($value) { >>> array_push($this->values, $value); >>> } >>> >>> public function addItem($value){ >>> $values = $this->values; >>> array_push($values, $value); >>> >>> $cloned = clone($this, ['values' => $values] >>> } >>> } >>> >>> $vo = new ValueObject(1); >>> $newVo = $vo->addItem(2); >>> >>> >>> >>> On Sep 7, 2016 12:52 PM, "Stephen Reay" <php-li...@koalephant.com >>> <mailto:php-li...@koalephant.com>> wrote: >>> Hi Silvio, >>> >>> Can you give an example of what you mean about passing properties that are >>> changing? >>> >>> Also, how would this affect e.g. an object that has objects or arrays as >>> members. >>> >>> It’s not always going to be just `$clone = clone $this; $clone->foo = >>> $foo;` - you could be adding/appending/removing array/object members too. >>> >>> Cheers >>> >>> Stephen >>> >>>> On 7 Sep 2016, at 17:43, Silvio Marijić <marijic.sil...@gmail.com >>>> <mailto:marijic.sil...@gmail.com>> wrote: >>>> >>>> @Stephan >>>> >>>> I am against that any kind of method can make modification on original >>>> object. >>>> >>>> Cloning can be allowed but for this use case where you would pass >>>> properties that are changing, we would have to modify syntax of clone >>>> >>>> On Sep 7, 2016 12:37 PM, "Stephen Reay" <php-li...@koalephant.com >>>> <mailto:php-li...@koalephant.com>> wrote: >>>> Hey Matheiu, Silvio, >>>> >>>> That is my main concern with the inability to clone from outside the >>>> class. I don’t think immutable should cause an error in this situation - >>>> if you really don’t want to allow users to create objects they can’t >>>> modify (which I understand) could clone on an immutable object from >>>> outside the class, simply return the object itself ? >>>> >>>> Re: immutable only externally - yes, as I mentioned I can understand that >>>> would be a deal-break for some. In that situation, I’d be happy with some >>>> way to indicate that a method can make changes. Would this then mean that >>>> such a method could modify the object itself, rather than the clone? >>>> >>>> Cheers >>>> >>>> Stephen >>>> >>>> > On 7 Sep 2016, at 17:09, Mathieu Rochette <math...@rochette.cc >>>> > <mailto:math...@rochette.cc>> wrote: >>>> > >>>> > >>>> > >>>> > On 07/09/2016 11:28, Silvio Marijić wrote: >>>> >> Hi Stephen, >>>> >> >>>> >> Cloning is disabled at the moment in implementation because you would >>>> >> end >>>> >> up with a object that you can not change, so you have no use of that. >>>> >> I'll >>>> >> change that as soon as we find some good solution for handling that. >>>> >> Your >>>> >> example is not really clear to me. At what point we should unlock/lock >>>> >> object based on your example? >>>> > what would happen if you tried to clone an immutable object, throw an >>>> > error ? >>>> > it means that you might have to use reflection to check if the object is >>>> > immutable before cloning it. otherwise making a class immutable would be >>>> > a BC >>>> >> >>>> >> DateTimeImmutable does not prevent cloning because immutability is >>>> >> achieved >>>> >> by encapsulation, and we want to get rid of the need of encapsulation in >>>> >> our implementation of immutable objects. >>>> >> >>>> >> Best, >>>> >> Silvio. >>>> >> >>>> >> 2016-09-07 11:05 GMT+02:00 Stephen Reay <php-li...@koalephant.com >>>> >> <mailto:php-li...@koalephant.com>>: >>>> >> >>>> >>> (Sorry for any dupes, sent from wrong address originally) >>>> >>> >>>> >>> From a developer point of view, I would suggest that a feature should >>>> >>> aim >>>> >>> to be as clear to understand with as little “magic" as possible. >>>> >>> >>>> >>> >>>> >>> If the goal of an immutable class is to allow public properties to be >>>> >>> made >>>> >>> read-only, my expectation would be that: >>>> >>> >>>> >>> - write access to any public property from outside class context, is an >>>> >>> error. >>>> >>> >>>> >>> This seems to be pretty much accepted by everyone >>>> >>> >>>> >>> >>>> >>> - clone still works as expected >>>> >>> >>>> >>> There has been some suggestion that clone $immutableObj should not be >>>> >>> allowed. Unless there is some specific language/engine gain by that, >>>> >>> what >>>> >>> is the point of having this behaviour? >>>> >>> Existing built-in immutable classes (like DateTimeImmutable) do not >>>> >>> prevent cloning, so why should this? >>>> >>> >>>> >>> - regular cloning from within class method(s) is the suggested way to >>>> >>> provide “create a copy of the object with a new value” functionality. >>>> >>> >>>> >>> This example was given before, effectively: >>>> >>> >>>> >>> public function withValue($val) { >>>> >>> $clone = clone $this; >>>> >>> $clone->val = $val; >>>> >>> >>>> >>> return $clone; >>>> >>> } >>>> >>> >>>> >>> >>>> >>> >>>> >>> >>>> >>> >>>> >>>> On 7 Sep 2016, at 13:57, Michał Brzuchalski <mic...@brzuchalski.com >>>> >>>> <mailto:mic...@brzuchalski.com>> >>>> >>> wrote: >>>> >>>> 06.09.2016 9:13 PM "Fleshgrinder" <p...@fleshgrinder.com >>>> >>>> <mailto:p...@fleshgrinder.com>> napisał(a): >>>> >>>>> I understand the concerns of all of you very well and it's nice to >>>> >>>>> see a >>>> >>>>> discussion around this topic. Fun fact, we are not the only ones with >>>> >>>>> these issues: https://github.com/dotnet/roslyn/issues/159 >>>> >>>>> <https://github.com/dotnet/roslyn/issues/159> >>>> >>>>> >>>> >>>>> On 9/6/2016 6:01 PM, Larry Garfield wrote: >>>> >>>>>> How big of a need is it to allow returning $this instead of $clone, >>>> >>>>>> and/or can that be internalized somehow as well? With >>>> >>>>>> copy-on-write, >>>> >>>>>> is that really an issue beyond a micro-optimization? >>>> >>>>> I asked the same question before because I am also unable to answer >>>> >>>>> this >>>> >>>>> question regarding the engine. >>>> >>>>> >>>> >>>>> However, for me it is more than micro-optimization, it is about >>>> >>> identity. >>>> >>>>> final class Immutable { >>>> >>>>> // ... the usual ... >>>> >>>>> public function withValue($value) { >>>> >>>>> $clone = clone $this; >>>> >>>>> $clone->value = $value; >>>> >>>>> return $clone; >>>> >>>>> } >>>> >>>>> } >>>> >>>>> >>>> >>>>> $red = new Immutable('red'); >>>> >>>>> $still_red = $red->withValue('red'); >>>> >>>>> >>>> >>>>> var_dump($red === $still_red); // bool(false) >>>> >>>>> >>>> >>>>> This is a problem in terms of value objects and PHP still does not >>>> >>>>> allow >>>> >>>>> us operator overloading. A circumstance that I definitely want to >>>> >>>>> address in the near future. >>>> >>>>> >>>> >>>>> But the keyword copy-on-write leads me to yet another proposal, >>>> >>>>> actually >>>> >>>>> your input led me to two new proposals. >>>> >>>>> >>>> >>>>> # Copy-on-Write (CoW) >>>> >>>>> Why are we even bothering on finding ways on making it hard for >>>> >>>>> developers while the solution to our problem is directly in front of >>>> >>>>> us: >>>> >>>>> PHP Strings! >>>> >>>>> >>>> >>>> AFAIK CoW in case of objects would be impossible to implement. >>>> >>>> >>>> >>>>> Every place in a PHP program refers to the same string if that >>>> >>>>> string is >>>> >>>>> the same string. In the second someone mutates that string in any way >>>> >>>>> she gets her own mutated reference to that string. >>>> >>>>> >>>> >>>>> That's exactly how we could deal with immutable objects. Developers >>>> >>>>> do >>>> >>>>> not need to take care of anything, they just write totally normal >>>> >>>>> objects and the engine takes care of everything. >>>> >>>>> >>>> >>>>> This approach also has the advantage that the return value of any >>>> >>>>> method >>>> >>>>> is (as always) up to the developers. >>>> >>>>> >>>> >>>>> (Cloning is disabled and results in an error as is because it makes >>>> >>>>> no >>>> >>>>> sense at all.) >>>> >>>>> >>>> >>>>> # Identity >>>> >>>>> This directly leads to the second part of my thoughts and I already >>>> >>>>> touched that topic: identity. If we have two strings their binary >>>> >>>>> representation is always the same: >>>> >>>>> >>>> >>>>> var_dump('string' === 'string'); // bool(true) >>>> >>>>> >>>> >>>>> This is the exact behavior one wants for value objects too. Hence, >>>> >>>>> immutable objects should have this behavior since they identify >>>> >>>>> themselves by their values and not through instances. If I create two >>>> >>>>> instances of Money with the amount 10 and the Currency EUR then they >>>> >>>>> are >>>> >>>>> always the same, no matter what. This would also mean that no >>>> >>>>> developer >>>> >>>>> ever needs to check if the new value is the same as the existing one, >>>> >>>>> nor does anyone ever has to implement the flyweight pattern for >>>> >>>>> immutable objects. >>>> >>>>> >>>> >>>>> A last very important attribute is that it does not matter in which >>>> >>>>> thread an immutable value object is created because it always has the >>>> >>>>> same identity regardless of it. >>>> >>>>> >>>> >>>>> This could easily be achieved by overwriting the object hashes >>>> >>>>> (spl_object_hash) with something that hashes based on the values, and >>>> >>>>> predictably across threads (UUIDs?). >>>> >>>>> >>>> >>>>> # Full Example >>>> >>>>> <?php >>>> >>>>> >>>> >>>>> final immutable class ValueObject { >>>> >>>>> >>>> >>>>> public $value; >>>> >>>>> >>>> >>>>> public function __construct($value) { >>>> >>>>> $this->value = $value; >>>> >>>>> } >>>> >>>>> >>>> >>>>> public function withValue($value) { >>>> >>>>> $this->value = $value; >>>> >>>>> } >>>> >>>>> >>>> >>>>> } >>>> >>>>> >>>> >>>>> class A { >>>> >>>>> >>>> >>>>> public $vo; >>>> >>>>> >>>> >>>>> public function __construct(ValueObject $vo) { >>>> >>>>> $this->vo = $vo; >>>> >>>>> } >>>> >>>>> >>>> >>>>> } >>>> >>>>> >>>> >>>>> class B { >>>> >>>>> >>>> >>>>> public $vo; >>>> >>>>> >>>> >>>>> public function __construct(ValueObject $vo) { >>>> >>>>> $this->vo = $vo; >>>> >>>>> } >>>> >>>>> >>>> >>>>> } >>>> >>>>> >>>> >>>>> $vo = new ValueObject(1); >>>> >>>>> >>>> >>>>> $a = new A($vo); >>>> >>>>> $b = new B($vo); >>>> >>>>> >>>> >>>>> var_dump($a->vo === $b->vo); // bool(true) >>>> >>>>> >>>> >>>>> $a->vo->withValue(2); >>>> >>>>> >>>> >>>>> var_dump($a->vo === $b->vo); // bool(false) >>>> >>>>> >>>> >>>>> $a->vo->withValue(1); >>>> >>>>> >>>> >>>>> var_dump($a->vo === $b->vo); // bool(true) >>>> >>>>> >>>> >>>>> // :) >>>> >>>>> >>>> >>>>> ?> >>>> >>>>> >>>> >>>>> -- >>>> >>>>> Richard "Fleshgrinder" Fussenegger >>>> >>>>> >>>> >>> >>>> >>> -- >>>> >>> PHP Internals - PHP Runtime Development Mailing List >>>> >>> To unsubscribe, visit: http://www.php.net/unsub.php >>>> >>> <http://www.php.net/unsub.php> >>>> >>> >>>> >>> >>>> >> >>>> > >>>> >>> >>> >>> >>> >>> -- >>> Silvio Marijić >>> Software Engineer >>> 2e Systems >> >> >> >> >> -- >> Silvio Marijić >> Software Engineer >> 2e Systems >