Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:95744 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 35925 invoked from network); 7 Sep 2016 12:19:59 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 7 Sep 2016 12:19:59 -0000 Authentication-Results: pb1.pair.com smtp.mail=marijic.silvio@gmail.com; spf=pass; sender-id=pass Authentication-Results: pb1.pair.com header.from=marijic.silvio@gmail.com; sender-id=pass Received-SPF: pass (pb1.pair.com: domain gmail.com designates 209.85.214.52 as permitted sender) X-PHP-List-Original-Sender: marijic.silvio@gmail.com X-Host-Fingerprint: 209.85.214.52 mail-it0-f52.google.com Received: from [209.85.214.52] ([209.85.214.52:38667] helo=mail-it0-f52.google.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id F7/D0-18051-AE500D75 for ; Wed, 07 Sep 2016 08:19:56 -0400 Received: by mail-it0-f52.google.com with SMTP id c198so17475545ith.1 for ; Wed, 07 Sep 2016 05:19:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :cc; bh=NF8mhmhS4a/FM1J3N5XW97Q07agYhFPsb7ENVpDLkbc=; b=TrwGb9DixzWsPaDFMfDhaLmbWAbeCbK2rYayFhIbBMPqXO3pt638z+skbYoRdFwrDi jTJHeW1dI9Fb8irtif9rr2S5nuXzwQ88TYlp03muDceBBVw74ptOEXzmO2/33k+GUXZB 5cwzrAOTbhJGEGvUICwR9w0FkWKmvou6d3kQI7U2qOhWj5kG1oMju76NsAdOfSvcQ+t/ cY9VDr+qQp0QlVqvlxkMJo7gELU/4qrTzkBpnmlKythmBwmOmv+eh6aL5NfC3xhbkT7t Fmqps9SqSg7kN8xpnXXDE/WolyLOe91B5A2LnlK1Mc3cSCAHTAyU6zM4/VlUZUpvx5yc uiow== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to:cc; bh=NF8mhmhS4a/FM1J3N5XW97Q07agYhFPsb7ENVpDLkbc=; b=I9bk8b2HS5PlT6IK/yQZtDYCkX2Oc0wLB6hjutqqsSW6Y8aq4CXKGytqTFc2GUGxP6 aPQ7xHI9GVCB0ewAFA3CbCZG7XNJ7XxUWDGUCv3jkaz8mMPpdMNMrMZDQI/citf3ey81 0v06EGUoYSKLlLgirNL/CX3B/6tSIIeJtKuEO+io3ehaukHRHUR3u7rIiJUX4qAhCWD0 n28MpRGJ6v9TzERH1+ZlZoizSRA8eqo4pYTYS/VZDo/zYgtmk8Crbbujsj4XerDi0hqH gzzMZdXj2HUh/F3Vb2molXv6KW04TeOLzeoVH6HtLDDQKI7ALQHvc+FO+8qQDVHGU7w2 GhKw== X-Gm-Message-State: AE9vXwMxOVt0vJylTxbyTjdMOHoHkXHnIqIjrlI8i8LO+NiXaebC0Y8AqNnOGuThNWrRDrrsuvvH0gVcdEod9g== X-Received: by 10.36.2.1 with SMTP id 1mr6028184itu.40.1473250789902; Wed, 07 Sep 2016 05:19:49 -0700 (PDT) MIME-Version: 1.0 Received: by 10.36.237.74 with HTTP; Wed, 7 Sep 2016 05:19: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:19:48 +0200 Message-ID: To: =?UTF-8?Q?Micha=C5=82_Brzuchalski?= Cc: Stephen Reay , Mathieu Rochette , PHP Internals List Content-Type: multipart/alternative; boundary=001a1143d5caff4e67053be9ed6c Subject: Re: [PHP-DEV] RFC - Immutable classes From: marijic.silvio@gmail.com (=?UTF-8?Q?Silvio_Mariji=C4=87?=) --001a1143d5caff4e67053be9ed6c Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable 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=C5=82 Brzuchalski = : > 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 >> method 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 >>> 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 chos= en >>> yet, we may discuss it or even vote for it. For now we can call it anyw= ay >>> 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 = can=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 ha= ppy 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 >>>> 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 woul= d >>>> be a >>>> > BC >>>> > >> >>>> > >> DateTimeImmutable does not prevent cloning because immutability i= s >>>> > 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 p= ossible. >>>> > >>> >>>> > >>> >>>> > >>> 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 =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 nic= e >>>> 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 abou= t >>>> > >>> 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 fo= r >>>> > >>>>> 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' =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 identif= y >>>> > >>>>> themselves by their values and not through instances. If I >>>> create two >>>> > >>>>> instances of Money with the amount 10 and the Currency EUR the= n >>>> 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 fo= r >>>> > >>>>> 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 >> > > > > -- > regards / pozdrawiam, > -- > Micha=C5=82 Brzuchalski > brzuchalski.com > --=20 Silvio Mariji=C4=87 Software Engineer 2e Systems --001a1143d5caff4e67053be9ed6c--