And also Fleshgrinder made a good point about comparing two immutable objects. They should be compared based on value, not on identity.
2016-09-07 11:28 GMT+02:00 Silvio Marijić <marijic.sil...@gmail.com>: > 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? > > 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 >> >> > > > -- > Silvio Marijić > Software Engineer > 2e Systems > -- Silvio Marijić Software Engineer 2e Systems