Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:95566 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 41846 invoked from network); 2 Sep 2016 14:27:52 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 2 Sep 2016 14:27:52 -0000 Authentication-Results: pb1.pair.com smtp.mail=larry@garfieldtech.com; spf=permerror; sender-id=unknown Authentication-Results: pb1.pair.com header.from=larry@garfieldtech.com; sender-id=unknown Received-SPF: error (pb1.pair.com: domain garfieldtech.com from 66.111.4.28 cause and error) X-PHP-List-Original-Sender: larry@garfieldtech.com X-Host-Fingerprint: 66.111.4.28 out4-smtp.messagingengine.com Received: from [66.111.4.28] ([66.111.4.28:52380] helo=out4-smtp.messagingengine.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id D7/67-19490-66C89C75 for ; Fri, 02 Sep 2016 10:27:51 -0400 Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.nyi.internal (Postfix) with ESMTP id 2119A2076C for ; Fri, 2 Sep 2016 10:27:48 -0400 (EDT) Received: from frontend2 ([10.202.2.161]) by compute3.internal (MEProxy); Fri, 02 Sep 2016 10:27:48 -0400 DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d= messagingengine.com; h=content-transfer-encoding:content-type :date:from:in-reply-to:message-id:mime-version:references :subject:to:x-sasl-enc:x-sasl-enc; s=smtpout; bh=8RMMHBrecuO1Pdg k6zSg0cFVOso=; b=LSVzfl6eZ9r5ZUllemmsbje42H+dLsmz92lSNUt0lICL/0n rfMsVx04/xx1QW8S2HaCxhyiv1loO5szxE/VD9+K7y1TD4HMNto4RQWPpIf92573 bh+eMYe04isMhsvun2GIxrMtkgUoFGgdaVBARoE+jaRpucBBal7UdwXDS2Q4= X-Sasl-enc: GkJm3PZFdp5YMrlLbpVo0xE187DpVKm/uQYJxSg7uevP 1472826467 Received: from [192.168.42.5] (c-50-178-40-84.hsd1.il.comcast.net [50.178.40.84]) by mail.messagingengine.com (Postfix) with ESMTPA id D513ECCE7E for ; Fri, 2 Sep 2016 10:27:47 -0400 (EDT) To: internals@lists.php.net 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> Message-ID: Date: Fri, 2 Sep 2016 09:27:47 -0500 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Thunderbird/45.2.0 MIME-Version: 1.0 In-Reply-To: Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 8bit Subject: Re: [PHP-DEV] RFC - Immutable classes From: larry@garfieldtech.com (Larry Garfield) On 09/02/2016 09:06 AM, Silvio Marijić wrote: > Well at the moment expection is thrown in case when you try to clone > immutable object. But you do seem to have valid point there regarding > __clone method. I'm definitely going to give it a thought. > > Best, > Silvio. > > 2016-09-02 15:52 GMT+02:00 André Rømcke : > >> >>> On Sep 2, 2016, at 09:10 , Silvio Marijić >> wrote: >>> Hi Fleshgrinder, >>> >>> Since Michal answered most of the questions, I'll just add some notes. >>> Initially I added restrictions to abstract classes, but I did think about >>> that over the last couple of days and couldn't find any concrete reason >> for >>> that restriction, so I think I'm going to remove that. As far as cloning, >>> it is disabled for immutable objects, because you'll end up with the copy >>> of object that you can not modify. I did mention in Cons sections that >>> cloning is disabled, maybe it should be made more clear. >> >> _If_ there are use-cases for it, wouldn’t it also be safe that the clone >> is allowed to be modified during __clone() and afterwards sealed? Like in >> __construct(). >> And if you don’t want to allow cloning, throw in __clone. >> >> Best, >> André I'd have to agree here. I love the idea of "lockable" immutable objects. However, the __clone() method has to be a modifiable area just like __construct() or else it's effectively useless for anything more than a trivial object. This was one of the main concerns with immutability in the PSR-7 discussions. Consider this sample class, with 8 properties (entirely reasonable for a complex value object): immutable class Record { public $a; public $b; public $c; public $d; public $e; public $f; public $g; public $h; public function __construct($a, $b, $c, $d, $e, $f, $g, $h) { $this->a = $a; $this->b = $b; $this->c = $c; $this->d = $d; $this->e = $e; $this->f = $f; $this->g = $g; $this->h = $h; } } Now I want a new value object that is the same, except that $d is incremented by 2. That is, I'm building up the value object over time rather than knowing everything at construct time. (This is exactly the use case of PSR-7.) I have to do this: $r1 = new Record(1, 2, 3, 4, 5, 6, 7, 8); $r2 - new Record($r1->a, $r1->b, $r1->c, $r1->d + 2, $1->e, $r1->f, $r1->g, $r1->h); That's crazy clunky, and makes immutable objects not very useful. Imagine a money object where you had to dissect it to its primitives, tweak one, and then repackage it just to add a dollar figure to it. That's not worth the benefit of being immutable. The way PSR-7 addressed that (using fake-immutability, basically), was this: class Response { // ... protected $statusCode; public function withStatusCode($code) { $new = clone($this); $new->statusCode = $code; return $new; } } That is, outside of the object there's no way to modify it in place, but it becomes super easy to get a slightly-modified version of the object: $r2 = $r1->withStatusCode(418); And because of PHP's copy-on-write support, it's actually surprisingly cheap. For language-level immutable objects, we would need some equivalent of that behavior. I'm not sure exactly what form it should take (explicit lock/unlock commands is all I can think of off hand, which I dislike), but that's the use case that would need to be addressed. --Larry Garfield