Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:95613 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 27618 invoked from network); 4 Sep 2016 08:55:57 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 4 Sep 2016 08:55:57 -0000 Authentication-Results: pb1.pair.com header.from=php@fleshgrinder.com; sender-id=unknown Authentication-Results: pb1.pair.com smtp.mail=php@fleshgrinder.com; spf=permerror; sender-id=unknown Received-SPF: error (pb1.pair.com: domain fleshgrinder.com from 212.232.25.164 cause and error) X-PHP-List-Original-Sender: php@fleshgrinder.com X-Host-Fingerprint: 212.232.25.164 mx208.easyname.com Received: from [212.232.25.164] ([212.232.25.164:33388] helo=mx208.easyname.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id 62/18-32927-C91EBC75 for ; Sun, 04 Sep 2016 04:55:57 -0400 Received: from cable-81-173-132-156.netcologne.de ([81.173.132.156] helo=[192.168.178.20]) by mx.easyname.com with esmtpsa (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.84_2) (envelope-from ) id 1bgTDU-0005CD-MB for internals@lists.php.net; Sun, 04 Sep 2016 08:55:52 +0000 Reply-To: internals@lists.php.net References: <99F80C06-654D-4109-BE07-2FA5B1073E5D@ez.no> <4f54308a-4a69-2e6b-2ed0-51d4336d1cd4@fleshgrinder.com> <5969d1af-48e5-1376-07fe-9568de538145@texthtml.net> To: internals@lists.php.net Message-ID: <0e71d28e-1d64-5372-b58d-e54c7afae3b8@fleshgrinder.com> Date: Sun, 4 Sep 2016 10:55:38 +0200 User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:45.0) Gecko/20100101 Thunderbird/45.2.0 MIME-Version: 1.0 In-Reply-To: Content-Type: multipart/signed; micalg=pgp-sha256; protocol="application/pgp-signature"; boundary="2RCDjP88fikavD2QrrVK1G0w2CWhbw2HT" Subject: Re: [PHP-DEV] RFC - Immutable classes From: php@fleshgrinder.com (Fleshgrinder) --2RCDjP88fikavD2QrrVK1G0w2CWhbw2HT Content-Type: multipart/mixed; boundary="aBWLD5DXOQLluxoKf7kFSTGqildU43h5E"; protected-headers="v1" From: Fleshgrinder Reply-To: internals@lists.php.net To: internals@lists.php.net Message-ID: <0e71d28e-1d64-5372-b58d-e54c7afae3b8@fleshgrinder.com> Subject: Re: [PHP-DEV] RFC - Immutable classes References: <167d6432-e4d6-d87d-5d31-d3d82a8de4ce@fleshgrinder.com> <99F80C06-654D-4109-BE07-2FA5B1073E5D@ez.no> <4f54308a-4a69-2e6b-2ed0-51d4336d1cd4@fleshgrinder.com> <5969d1af-48e5-1376-07fe-9568de538145@texthtml.net> In-Reply-To: --aBWLD5DXOQLluxoKf7kFSTGqildU43h5E Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Hi Chris! On 9/3/2016 5:00 PM, Chris Riley wrote: > - Properties can be declared immutable. Immutable properties may only b= e > changed under two circumstances: a) In the objects constructor b) If th= ey > are null (This enables setter injection if required) > The constraint b) would make the object mutable and defeat the purpose of the immutable modifier since any property could change at any time if it was NULL at the beginning. Requiring syncing in concurrent environment= s. On 9/3/2016 5:00 PM, Chris Riley wrote: > - Arrays assigned to immutable properties would not be possible to chan= ge > Array support would definitely be very nice. I mean, we have constant arrays already, hence, it is possible. On 9/3/2016 5:00 PM, Chris Riley wrote: > - Objects assigned to immutable properties would be possible to change,= so > long as the same object remained assigned to the property. >=20 This would once more lead to mutability and the constraint of immutability would be violated. On 9/3/2016 5:00 PM, Chris Riley wrote: > From a developer adoption point of view, I think these two points are > important to making immutable classes generally useful. Without 1, it w= ill > be a nuisance to use 3rd party libraries esp those which retain > compatibility for PHP < 7.2. Without 2 you block the ability to use set= ter > injection, which I personally would be in favour of if it meant that de= vs > stopped using it - it wouldn't - they would simply not use immutable > classes, loosing the benefits thereof. >=20 The adoption of the feature will be halted until 7.2 is widely available in bigger projects. That is most certainly right. However, we should aim for the best, most useful, and future proof solution and not towards the one that's adopted very fast but lacks some important constraints. Having truly immutable objects is required in concurrent scenarios and such scenarios are in the future for PHP and not in the past. Regarding setter injection: I do not see the need for it at all in the context of immutable objects. In the end we are talking about value objects here and they should not have any optional dependencies. Maybe you could come up with a use case to illustrate the need? On 9/3/2016 5:00 PM, Chris Riley wrote: > Dealing with the clone issue some of my ideas since then were: >=20 > - Seal/Unseal (As per Larry's suggestion) > - Parameters to __clone; in this instance the clone method would be all= owed > to change properties of the object as well as the constructor. This fee= ls > like it may breach the principal of least surprise as cloning an object= no > longer guarantees an exact copy. > - A new magic method __mutate($property, $newvalue) called instead of a= > fatal error when a property is changed. This probably lays too many tra= ps > for developers for it to be a good idea. > - Implicitly returning a new object whenever a property is changed. Sim= ilar > reservations to the above. > - A new magic method __with($newInstance, $args) and a keyword with tha= t is > used in place of clone eg $x =3D $y with ($arg1, $arg2); in this instan= ce, > __with receives a clone of $y (after calling __clone) and an array [$ar= g1, > $arg2] the with magic method is allowed to mutate $newInstance and must= > return it. This is currently my favoured solution >=20 How does one know which property is to be mutated in the __with method? You should also not underestimate the performance hit and the branching since you only want to change the properties that changed based on the data from the passed array. I have a third proposal after giving this some more thought. Inspired by Rust's approach to mark mutation explicitly. final immutable class ValueObject { public $value; public mutator [function] withValue($clone, $value): static { $clone->value =3D $value; } } A mutator function always receives the mutable clone as first argument and always returns that one. Users can have a return but they must return the clone (hence the static return type declaration). $vo1 =3D new ValueObject(1); $vo2 =3D $vo1->withValue(2); Calls are of course without the clone as it is handled by the engine. There is no special branching necessary and no performance hit at all while the logic is kept in the place where it is required. --=20 Richard "Fleshgrinder" Fussenegger --aBWLD5DXOQLluxoKf7kFSTGqildU43h5E-- --2RCDjP88fikavD2QrrVK1G0w2CWhbw2HT Content-Type: application/pgp-signature; name="signature.asc" Content-Description: OpenPGP digital signature Content-Disposition: attachment; filename="signature.asc" -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAEBCAAGBQJXy+GUAAoJEOKkKcqFPVVri88P/0M04qIvD4hOIG3Zus0u1zro QRSoqCEl8fs3XvBmsIPG6MEHOHXN/eyuo1Ouy0pelMiQrnlZaTovWQWw13kOkwcR WrC07SBYwWEVlnfGcdmLxXyjG2Urt4CKaHRAcXfeOFiG9ZuVKcaKjDCClpF53aBU BR2TUMy3PkwsXGTpgEgE1w5b1pWk62toV+Jm6GOzauzNqn+fcT5/fOFd5lkPa8Gl cvqVONyXaE6epjgbhwM8HvbSpKF65hTmuedzAdg08gCMwNd0HH/WMTveIqOfUaY2 gJ00naDZg85Gssucetz0cB/CRGz3NW3xt56V7N7X0hB0mjVq/JJAkL5s4JKTnDCA vvql6KSGUpuuN4o0ZgY+uyI+DvUcP/Wm8aVRkFKEDIb5m3J3S6bBMm4wXQvL1z/q jKIRaUujRH8JIOYU9UhTU1ndzEdVPautBJG97JE6amgzmGAYEx6MwHl18+MDE48N b19us4bZwYdDlvzXohCpjAM/VkeCQLFizYwPTCnhuzw5YW/loI0ZLQnAm91aOqt+ zo/sTaV/LjWTyvIxiCE7CihrlvItd3eJFhEvvK/UNqvfMnXsGUouhVBcIj1wlgpg TsWTDvTa0rwfQ4wK8ijJ0whjhy1e7l72NGsc/a0MMeTh3NsyYVXisbMvrnRAVlBz N+7eH+UVZyYNMSIBT0om =rbL2 -----END PGP SIGNATURE----- --2RCDjP88fikavD2QrrVK1G0w2CWhbw2HT--