Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:95710 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 36881 invoked from network); 7 Sep 2016 06:57:34 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 7 Sep 2016 06:57:34 -0000 Authentication-Results: pb1.pair.com header.from=michal@brzuchalski.com; sender-id=pass Authentication-Results: pb1.pair.com smtp.mail=michal@brzuchalski.com; spf=pass; 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:50142] helo=poczta.brzuchalski.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id 1F/F4-18051-95ABFC75 for ; Wed, 07 Sep 2016 02:57:31 -0400 Received: from localhost (localhost.localdomain [127.0.0.1]) by poczta.brzuchalski.com (Postfix) with ESMTP id 45CCF2984243 for ; Wed, 7 Sep 2016 08:57:25 +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 PEB_K47Hcz0Y for ; Wed, 7 Sep 2016 08:57:20 +0200 (CEST) Received: from mail-qk0-f173.google.com (unknown [209.85.220.173]) by poczta.brzuchalski.com (Postfix) with ESMTPSA id 5CAE52984241 for ; Wed, 7 Sep 2016 08:57:18 +0200 (CEST) Received: by mail-qk0-f173.google.com with SMTP id w204so3260481qka.0 for ; Tue, 06 Sep 2016 23:57:18 -0700 (PDT) X-Gm-Message-State: AE9vXwM55pNCXjH11Kh+ckjKmg96JGikbDz0P+DtbwpbB00d10KqI3Jsgvl+ctxXGJUNzb6S4ymGSVVyz1jgLg== X-Received: by 10.55.181.193 with SMTP id e184mr47727050qkf.233.1473231437909; Tue, 06 Sep 2016 23:57:17 -0700 (PDT) MIME-Version: 1.0 Received: by 10.200.56.100 with HTTP; Tue, 6 Sep 2016 23:57:16 -0700 (PDT) Received: by 10.200.56.100 with HTTP; Tue, 6 Sep 2016 23:57:16 -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> Date: Wed, 7 Sep 2016 08:57:16 +0200 X-Gmail-Original-Message-ID: Message-ID: To: PHP Internals List Cc: Larry Garfield , =?UTF-8?Q?Silvio_Mariji=C4=87?= Content-Type: multipart/alternative; boundary=94eb2c06229c875759053be56c35 Subject: Re: [PHP-DEV] RFC - Immutable classes From: michal@brzuchalski.com (=?UTF-8?Q?Micha=C5=82_Brzuchalski?=) --94eb2c06229c875759053be56c35 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable 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 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 =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 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 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 > > 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 > --94eb2c06229c875759053be56c35--