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