Ok, I have some time also so we can together try to write some initial implementation of that.
2016-09-07 14:10 GMT+02:00 Michał Brzuchalski <mic...@brzuchalski.com>: > Silvio, > > I can try with it tommorow, we'll see about that. > > > 2016-09-07 14:05 GMT+02:00 Silvio Marijić <marijic.sil...@gmail.com>: > >> Michal, how much work do you estimate it would take us to implement >> method modificator solution? >> >> 2016-09-07 14:01 GMT+02:00 Michał Brzuchalski <mic...@brzuchalski.com>: >> >>> Hi, >>> >>> Frozing an immutable object after it's creation is most important >>> feature of Immutable Classes. >>> Without it you cannot have guarantee it's internal state is consistent >>> as it was during creation. >>> Having methods access to write is quite dangerous - think about CLosure >>> binded to immutable object - there is a way to change internal state of >>> such object, and you've broken immutability in it. >>> >>> Changing object state is reasonable only on clones, because you newer >>> know what references to original object. >>> There can be cloning objects as they are now - I don't see it usefull, >>> but if somebody really want's it, why not. >>> >>> IMHO providing method modificator for changing object in context of >>> newly created clone is the best solution. The keyword for it isn't chosen >>> yet, we may discuss it or even vote for it. For now we can call it anyway >>> while keeping in mind it may change during voting. >>> >>> >>> >>> 2016-09-07 12:43 GMT+02:00 Silvio Marijić <marijic.sil...@gmail.com>: >>> >>>> @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> >>>> 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> >>>> 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 >>>> >: >>>> > >> >>>> > >>> (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> >>>> > >>> wrote: >>>> > >>>> 06.09.2016 9:13 PM "Fleshgrinder" <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 >>>> > >>>>> >>>> > >>>>> 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 >>>> > >>> >>>> > >>> >>>> > >> >>>> > > >>>> > >>>> > >>>> >>> >>> >>> >>> -- >>> regards / pozdrawiam, >>> -- >>> Michał Brzuchalski >>> brzuchalski.com >>> >> >> >> >> -- >> Silvio Marijić >> Software Engineer >> 2e Systems >> > > > > -- > regards / pozdrawiam, > -- > Michał Brzuchalski > brzuchalski.com > -- Silvio Marijić Software Engineer 2e Systems