Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:95753 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 65976 invoked from network); 7 Sep 2016 14:02:24 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 7 Sep 2016 14:02:24 -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.41 as permitted sender) X-PHP-List-Original-Sender: marijic.silvio@gmail.com X-Host-Fingerprint: 209.85.214.41 mail-it0-f41.google.com Received: from [209.85.214.41] ([209.85.214.41:34977] helo=mail-it0-f41.google.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id AD/72-43559-FED10D75 for ; Wed, 07 Sep 2016 10:02:23 -0400 Received: by mail-it0-f41.google.com with SMTP id e124so198205974ith.0 for ; Wed, 07 Sep 2016 07:02:23 -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=zdOv2U1Tp3sbyBCBUMebxnrxFcKUaT796c7w1zJfCPM=; b=Uyhvv74iKTYby3+n8PndG15QfQ5kw/1JhuQ5yJDsadfeTJW7oTaDYRWx4Hj6UznmbL TuVEP3MRg2JCs1bRcr9bAalSFEyK56kqs9ATehnDEhyyvZYqSlWoXqzGv1EnGSVh1mgz 4wNf/gPU7FO5+r6hwS8yvU1ZXMrU6vdHVTa37texoO3g+3hcxwjPzx2609039xJ/3WuD lKH/XuqenEnGH18YRMZ1eX+n7yQCgSEnvLBU2vBv1zn8gaCW/hNm7SDmrh5F4YkNgZU+ cF4mx8ShituqTsrizogdKtRsDklFSKNDR9lUGm8/jFcalGg5cJ++nkDygLOy8Mn9e3ow xPXw== 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=zdOv2U1Tp3sbyBCBUMebxnrxFcKUaT796c7w1zJfCPM=; b=gWhd/K5WjR9i7sEO0MuMRfQ7Boi5ewIssHWB4nbavSlg/l5Hd/+Su5GUvPM3sSwxht gZuDup26JsARQwmniVg6ksIwPiV8klrvzgneA7DhNmfMVMLstrpcx/TFttcrcv6s310T K+j+w15Q4e98+uvzmnNJvLNnSqcuI4BXCks84XCynIT7FYtDbsbgupgCFhpcDUcEMEkZ 75T0+Jk7oWrwfGdHi2QwyXuInO7hEox7QcS8kenPN69plLgYIbjlrYnnxkqpFcdmWSGl E2QkgV4XWhusDivASb4imjLY9cR+hQI7si+kX5vWi5w2dUxBeDvmSTbq+xuPZ4hK8Z7p 6QBQ== X-Gm-Message-State: AE9vXwP9DZZ0xMEyzlIlPdokoe+ysJe3O3HEFooI0KW+4GXr3agbmpwu7sgWWGWGodPGsRBHWpVJUwSVlQMWdw== X-Received: by 10.36.111.209 with SMTP id x200mr6403901itb.59.1473256940673; Wed, 07 Sep 2016 07:02:20 -0700 (PDT) MIME-Version: 1.0 Received: by 10.36.237.74 with HTTP; Wed, 7 Sep 2016 07:02:19 -0700 (PDT) In-Reply-To: References: <4f54308a-4a69-2e6b-2ed0-51d4336d1cd4@fleshgrinder.com> <5969d1af-48e5-1376-07fe-9568de538145@texthtml.net> <0e71d28e-1d64-5372-b58d-e54c7afae3b8@fleshgrinder.com> Date: Wed, 7 Sep 2016 16:02:19 +0200 Message-ID: To: Mathieu Rochette Cc: =?UTF-8?Q?Micha=C5=82_Brzuchalski?= , PHP Internals List Content-Type: multipart/alternative; boundary=001a11450cac9ca72c053beb5cec Subject: Re: [PHP-DEV] RFC - Immutable classes From: marijic.silvio@gmail.com (=?UTF-8?Q?Silvio_Mariji=C4=87?=) --001a11450cac9ca72c053beb5cec Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable @Lester I might have expressed my self in a wrong way, there is not wrong with encapsulation. Thing is that there is no proper support and unified solution from the language. There are much examples of real world cases where this can be useful. I understand that same behaviour can be achieved on multiple different ways without moving that to the language it's self, that is not a question at all. As I said in RFC, goal is to bring one solution which can be easily enforced and move that from the the developer to the language to take care of that. Cheers 2016-09-07 15:24 GMT+02:00 Mathieu Rochette : > > > On 07/09/2016 15:09, Micha=C5=82 Brzuchalski wrote: > >> @Mathieu How about that: https://gist.github.com/brzuch >> al/e7b721e22a19cca42ec0d1f597a23baf >> We've discussed this could be best option, when invoking `transformer` >> method (or whatever we call it) >> there is `$this =3D clone $this` invoked under the hood. >> > I don't know, it seems a bit strange to override $this . I can't have the > original object and the new one at the same time. > Or do you mean I also have the option to do "$clone =3D clone $this" ? > >> >> 2016-09-07 14:53 GMT+02:00 Mathieu Rochette > mathieu@rochette.cc>>: >> >> a few remarks on mutator methods: >> >> * It could be a nice way to solve the "create another one almost >> the same" use case. >> * I don't mind if $clone is an explicit parameter or magically >> available >> * what happens if I call other function/methods with this $clone >> before the end of the function ? >> * and the only downside: I have to make a method just for >> >> cloning. that means I have to call a mutator multiple times if >> I want to make a bunch of clone, eg: >> >> because of the last point, I think I'd like the seal the clone at >> then end of the block/method better, here are 2 examples to >> illustrate what I mean >> >> class immutable foo { >> private $prop =3D 0; >> >> public function __construct($v) {$this->prop =3D $v;} >> >> public function bar(obj $o) { >> $e->makeSomethingWith($this->cloneAndEdit(42)); >> } >> >> public function many($n) { >> $a =3D []; >> for ($i =3D 0; $i < $n; $i++) { >> $a[] =3D $this->cloneAndEdit($i)); >> } >> return $a; >> >> } >> >> public function mut cloneAndEdit($n) { >> $clone->prop =3D $n; >> } >> } >> >> // vs >> >> class immutable foo { >> private $prop =3D 0; >> >> public function __construct($v) {$this->prop =3D $v;} >> >> public function bar(obj $o) { >> $c =3D $clone $this; >> $c->prop =3D 42; >> $e->makeSomethingWith($c); >> } >> >> public function many($n) { >> $a =3D []; >> for ($i =3D 0; $i < $n; $i++) { >> $a[] =3D $c =3D $clone $this; >> $c->prop =3D 42; >> } >> return $a; >> } >> } >> >> I understand that it's still not clear exactly when the object >> should be sealed but if it can works this one would have my preferen= ce >> >> On 04/09/2016 14:10, Micha=C5=82 Brzuchalski wrote: >> >>> 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 t= o >>>>> 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 point= s >>>>> 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 u= se >>>>> >>>> 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 valu= e >>>> 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 >>>>> object >>>>> >>>> no >>>> >>>>> longer guarantees an exact copy. >>>>> - A new magic method __mutate($property, $newvalue) called instea= d >>>>> 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 change= d. >>>>> >>>> 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 >>>>> instance, >>>>> __with receives a clone of $y (after calling __clone) and an arra= y >>>>> >>>> [$arg1, >>>> >>>>> $arg2] the with magic method is allowed to mutate $newInstance an= d >>>>> must >>>>> 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 coul= d >>> break >>> 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 breaki= ng >>> 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` but >>> not `$this` >>> but I don't see the need of it - assuming there is no what to chang= e >>> 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. >>> >>> >>> 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 Silvio Mariji=C4=87 Software Engineer 2e Systems --001a11450cac9ca72c053beb5cec--