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