Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:95742 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 31959 invoked from network); 7 Sep 2016 12:11:05 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 7 Sep 2016 12:11:05 -0000 Authentication-Results: pb1.pair.com smtp.mail=michal@brzuchalski.com; spf=pass; sender-id=pass Authentication-Results: pb1.pair.com header.from=michal@brzuchalski.com; sender-id=pass Received-SPF: pass (pb1.pair.com: domain brzuchalski.com designates 188.165.245.118 as permitted sender) X-PHP-List-Original-Sender: michal@brzuchalski.com X-Host-Fingerprint: 188.165.245.118 ns220893.ip-188-165-245.eu Received: from [188.165.245.118] ([188.165.245.118:57583] helo=poczta.brzuchalski.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id 93/40-18051-4D300D75 for ; Wed, 07 Sep 2016 08:11:01 -0400 Received: from localhost (localhost.localdomain [127.0.0.1]) by poczta.brzuchalski.com (Postfix) with ESMTP id 0DA572984249 for ; Wed, 7 Sep 2016 14:10:58 +0200 (CEST) Received: from poczta.brzuchalski.com ([127.0.0.1]) by localhost (poczta.brzuchalski.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id BTwWL4iVGqhB for ; Wed, 7 Sep 2016 14:10:54 +0200 (CEST) Received: from mail-qk0-f182.google.com (unknown [209.85.220.182]) by poczta.brzuchalski.com (Postfix) with ESMTPSA id EF963298424B for ; Wed, 7 Sep 2016 14:10:50 +0200 (CEST) Received: by mail-qk0-f182.google.com with SMTP id m184so6616816qkb.1 for ; Wed, 07 Sep 2016 05:10:50 -0700 (PDT) X-Gm-Message-State: AE9vXwM6UwSo2pZ3aqYZ1FDU+/eif88tnggR/GEemxKmcxfrympjTNDwYA5h7TUfIkSndv153+3Hnmwgd4rCwA== X-Received: by 10.55.179.197 with SMTP id c188mr49620887qkf.7.1473250250169; Wed, 07 Sep 2016 05:10:50 -0700 (PDT) MIME-Version: 1.0 Received: by 10.200.56.100 with HTTP; Wed, 7 Sep 2016 05:10:48 -0700 (PDT) In-Reply-To: References: <0e71d28e-1d64-5372-b58d-e54c7afae3b8@fleshgrinder.com> <642a6e78-90ea-cbf0-ec1c-376c24e568c5@fleshgrinder.com> <0800a5ca-3d14-c541-1a1a-2574ec802b8c@fleshgrinder.com> <83fa661e-2d3d-6548-a506-fb969be31c0e@garfieldtech.com> <69D0D60B-3D42-4228-8156-F9E6AFEDF72B@koalephant.com> <388c9bf3-d7bc-7e73-bf44-b4c446c2398b@rochette.cc> Date: Wed, 7 Sep 2016 14:10:48 +0200 X-Gmail-Original-Message-ID: Message-ID: To: =?UTF-8?Q?Silvio_Mariji=C4=87?= Cc: Stephen Reay , Mathieu Rochette , PHP Internals List Content-Type: multipart/alternative; boundary=94eb2c0658ecd3a7e6053be9cda7 Subject: Re: [PHP-DEV] RFC - Immutable classes From: michal@brzuchalski.com (=?UTF-8?Q?Micha=C5=82_Brzuchalski?=) --94eb2c0658ecd3a7e6053be9cda7 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Silvio, I can try with it tommorow, we'll see about that. 2016-09-07 14:05 GMT+02:00 Silvio Mariji=C4=87 : > Michal, how much work do you estimate it would take us to implement metho= d > modificator solution? > > 2016-09-07 14:01 GMT+02:00 Micha=C5=82 Brzuchalski : > >> Hi, >> >> Frozing an immutable object after it's creation is most important featur= e >> of Immutable Classes. >> Without it you cannot have guarantee it's internal state is consistent a= s >> 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 newl= y >> 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=C4=87 : >> >>> @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" >>> wrote: >>> >>> > Hey Matheiu, Silvio, >>> > >>> > That is my main concern with the inability to clone from outside the >>> > class. I don=E2=80=99t think immutable should cause an error in this = situation >>> - if >>> > you really don=E2=80=99t want to allow users to create objects they c= an=E2=80=99t >>> 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=E2=80=99d be hap= py 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 >>> wrote: >>> > > >>> > > >>> > > >>> > > On 07/09/2016 11:28, Silvio Mariji=C4=87 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 tha= t. >>> > 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 = : >>> > >> >>> > >>> (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 =E2=80=9Cmagic" as po= ssible. >>> > >>> >>> > >>> >>> > >>> If the goal of an immutable class is to allow public properties t= o >>> 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 no= t >>> 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 n= ot >>> > >>> prevent cloning, so why should this? >>> > >>> >>> > >>> - regular cloning from within class method(s) is the suggested wa= y >>> to >>> > >>> provide =E2=80=9Ccreate a copy of the object with a new value=E2= =80=9D >>> functionality. >>> > >>> >>> > >>> This example was given before, effectively: >>> > >>> >>> > >>> public function withValue($val) { >>> > >>> $clone =3D clone $this; >>> > >>> $clone->val =3D $val; >>> > >>> >>> > >>> return $clone; >>> > >>> } >>> > >>> >>> > >>> >>> > >>> >>> > >>> >>> > >>> >>> > >>>> On 7 Sep 2016, at 13:57, Micha=C5=82 Brzuchalski < >>> michal@brzuchalski.com> >>> > >>> wrote: >>> > >>>> 06.09.2016 9:13 PM "Fleshgrinder" >>> napisa=C5=82(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 one= s >>> 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 =3D clone $this; >>> > >>>>> $clone->value =3D $value; >>> > >>>>> return $clone; >>> > >>>>> } >>> > >>>>> } >>> > >>>>> >>> > >>>>> $red =3D new Immutable('red'); >>> > >>>>> $still_red =3D $red->withValue('red'); >>> > >>>>> >>> > >>>>> var_dump($red =3D=3D=3D $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 norm= al >>> > >>>>> objects and the engine takes care of everything. >>> > >>>>> >>> > >>>>> This approach also has the advantage that the return value of a= ny >>> > 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 bina= ry >>> > >>>>> representation is always the same: >>> > >>>>> >>> > >>>>> var_dump('string' =3D=3D=3D '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 existin= g >>> 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 >>> > >>>>> >> > >>>>> >>> > >>>>> final immutable class ValueObject { >>> > >>>>> >>> > >>>>> public $value; >>> > >>>>> >>> > >>>>> public function __construct($value) { >>> > >>>>> $this->value =3D $value; >>> > >>>>> } >>> > >>>>> >>> > >>>>> public function withValue($value) { >>> > >>>>> $this->value =3D $value; >>> > >>>>> } >>> > >>>>> >>> > >>>>> } >>> > >>>>> >>> > >>>>> class A { >>> > >>>>> >>> > >>>>> public $vo; >>> > >>>>> >>> > >>>>> public function __construct(ValueObject $vo) { >>> > >>>>> $this->vo =3D $vo; >>> > >>>>> } >>> > >>>>> >>> > >>>>> } >>> > >>>>> >>> > >>>>> class B { >>> > >>>>> >>> > >>>>> public $vo; >>> > >>>>> >>> > >>>>> public function __construct(ValueObject $vo) { >>> > >>>>> $this->vo =3D $vo; >>> > >>>>> } >>> > >>>>> >>> > >>>>> } >>> > >>>>> >>> > >>>>> $vo =3D new ValueObject(1); >>> > >>>>> >>> > >>>>> $a =3D new A($vo); >>> > >>>>> $b =3D new B($vo); >>> > >>>>> >>> > >>>>> var_dump($a->vo =3D=3D=3D $b->vo); // bool(true) >>> > >>>>> >>> > >>>>> $a->vo->withValue(2); >>> > >>>>> >>> > >>>>> var_dump($a->vo =3D=3D=3D $b->vo); // bool(false) >>> > >>>>> >>> > >>>>> $a->vo->withValue(1); >>> > >>>>> >>> > >>>>> var_dump($a->vo =3D=3D=3D $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=C5=82 Brzuchalski >> brzuchalski.com >> > > > > -- > Silvio Mariji=C4=87 > Software Engineer > 2e Systems > --=20 regards / pozdrawiam, -- Micha=C5=82 Brzuchalski brzuchalski.com --94eb2c0658ecd3a7e6053be9cda7--