Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:95618 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 67292 invoked from network); 4 Sep 2016 12:29:38 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 4 Sep 2016 12:29:38 -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:49567] helo=poczta.brzuchalski.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id C7/11-45301-0B31CC75 for ; Sun, 04 Sep 2016 08:29:37 -0400 Received: from localhost (localhost.localdomain [127.0.0.1]) by poczta.brzuchalski.com (Postfix) with ESMTP id 7122B2984235 for ; Sun, 4 Sep 2016 14:29:32 +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 LVhJRGDej9pm for ; Sun, 4 Sep 2016 14:29:28 +0200 (CEST) Received: from mail-qt0-f177.google.com (unknown [209.85.216.177]) by poczta.brzuchalski.com (Postfix) with ESMTPSA id 3DC672984233 for ; Sun, 4 Sep 2016 14:29:28 +0200 (CEST) Received: by mail-qt0-f177.google.com with SMTP id 93so81975566qtg.2 for ; Sun, 04 Sep 2016 05:29:28 -0700 (PDT) X-Gm-Message-State: AE9vXwN3JDC5R9rLEtY7Fg+4FITLDzn/r2k7Z2JPA7M/8lpJiGpCw3IkB47Ba8r5bv6Fp5wCTRMV8edWtwdcdw== X-Received: by 10.200.57.71 with SMTP id t7mr9138601qtb.80.1472992167424; Sun, 04 Sep 2016 05:29:27 -0700 (PDT) MIME-Version: 1.0 Received: by 10.200.56.100 with HTTP; Sun, 4 Sep 2016 05:29:26 -0700 (PDT) In-Reply-To: References: <99F80C06-654D-4109-BE07-2FA5B1073E5D@ez.no> <4f54308a-4a69-2e6b-2ed0-51d4336d1cd4@fleshgrinder.com> <5969d1af-48e5-1376-07fe-9568de538145@texthtml.net> <0e71d28e-1d64-5372-b58d-e54c7afae3b8@fleshgrinder.com> Date: Sun, 4 Sep 2016 14:29:26 +0200 X-Gmail-Original-Message-ID: Message-ID: To: PHP Internals List Content-Type: multipart/alternative; boundary=001a113eddc2e588f2053badb6a9 Subject: Re: [PHP-DEV] RFC - Immutable classes From: michal@brzuchalski.com (=?UTF-8?Q?Micha=C5=82_Brzuchalski?=) --001a113eddc2e588f2053badb6a9 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable 2016-09-04 14:10 GMT+02:00 Micha=C5=82 Brzuchalski = : > > > 2016-09-04 10:55 GMT+02:00 Fleshgrinder : > >> Hi Chris! >> >> On 9/3/2016 5:00 PM, Chris Riley wrote: >> > - Properties can be declared immutable. Immutable properties may only = be >> > changed under two circumstances: a) In the objects constructor b) If >> they >> > 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 >> environments. >> >> On 9/3/2016 5:00 PM, Chris Riley wrote: >> > - Arrays assigned to immutable properties would not be possible to >> change >> > >> >> 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. >> > >> >> 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 >> will >> > 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 >> setter >> > injection, which I personally would be in favour of if it meant that >> devs >> > stopped using it - it wouldn't - they would simply not use immutable >> > classes, loosing the benefits thereof. >> > >> >> 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: >> > >> > - Seal/Unseal (As per Larry's suggestion) >> > - Parameters to __clone; in this instance the clone method would be >> allowed >> > to change properties of the object as well as the constructor. This >> feels >> > like it may breach the principal of least surprise as cloning an objec= t >> 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 >> traps >> > for developers for it to be a good idea. >> > - Implicitly returning a new object whenever a property is changed. >> Similar >> > reservations to the above. >> > - A new magic method __with($newInstance, $args) and a keyword with >> that is >> > used in place of clone eg $x =3D $y with ($arg1, $arg2); in this insta= nce, >> > __with receives a clone of $y (after calling __clone) and an array >> [$arg1, >> > $arg2] the with magic method is allowed to mutate $newInstance and mus= t >> > return it. This is currently my favoured solution >> > >> >> 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; >> } >> >> } >> >> > Providing `mutator` | `mut` keyword as method modifier sounds liek a good > idea, > althought passing `$clone` parameter as first additional param could brea= k > method declaration and would be misleading. > > Assuming mutator method is designed to return mutated clone of immutable > object > having `$clone` variable could be handled internally without breaking > method declaration. > > Such variable could be unlocked while in mutator method and locked on > return. > I was thinking about additional check if such mutator returns `$clone` bu= t > not `$this` > but I don't see the need of it - assuming there is no what to change in > some > circumstances ther would be also possible to return `$this`. > > The return type declaration `self` could increase readability, but should > not be required, > as some developers doesn't already use return types. > It could look like in this gist https://gist.github.com/brzuchal/e7b721e22a19cca42ec0d1f597a23baf > > >> 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. >> >> -- >> Richard "Fleshgrinder" Fussenegger >> >> > > > -- > regards / pozdrawiam, > -- > Micha=C5=82 Brzuchalski > brzuchalski.com > --=20 regards / pozdrawiam, -- Micha=C5=82 Brzuchalski brzuchalski.com --001a113eddc2e588f2053badb6a9--