Newsgroups: php.internals
Path: news.php.net
Xref: news.php.net php.internals:95954
Return-Path: <larry@garfieldtech.com>
Mailing-List: contact internals-help@lists.php.net; run by ezmlm
Delivered-To: mailing list internals@lists.php.net
Received: (qmail 51909 invoked from network); 12 Sep 2016 20:11:46 -0000
Received: from unknown (HELO lists.php.net) (127.0.0.1)
  by localhost with SMTP; 12 Sep 2016 20:11:46 -0000
Authentication-Results: pb1.pair.com header.from=larry@garfieldtech.com; sender-id=unknown
Authentication-Results: pb1.pair.com smtp.mail=larry@garfieldtech.com; spf=permerror; 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:53001] helo=out4-smtp.messagingengine.com)
	by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP
	id 41/00-51547-10C07D75 for <internals@lists.php.net>; Mon, 12 Sep 2016 16:11:45 -0400
Received: from compute3.internal (compute3.nyi.internal [10.202.2.43])
	by mailout.nyi.internal (Postfix) with ESMTP id 6EA4C209DA
	for <internals@lists.php.net>; Mon, 12 Sep 2016 16:11:42 -0400 (EDT)
Received: from frontend1 ([10.202.2.160])
  by compute3.internal (MEProxy); Mon, 12 Sep 2016 16:11:42 -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=XR/2PUX8vCck8To
	jSB8rSgd029o=; b=E4JJssQ3/9cqpw30uROFlN5ZWzvI9Z4RYxLXV7FsjNcwI5p
	34/fWyOpKhVnMEKVyoKbvBLTGhMTXg7A5el+r6t5tOmi9YvJb9f7aa2+kAuFmZNm
	Jk1VKcH/OZ7WvuUWPbo7hp0eBVMBXL9HX6eS9fOoEs+tyzflYkurRgvE1btc=
X-Sasl-enc: sHOHgZZFCQTJfuuq+cIw1UH1XlRJtJLTkEp01gWKOmrm 1473711102
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 11D7EF29CF
	for <internals@lists.php.net>; Mon, 12 Sep 2016 16:11:42 -0400 (EDT)
To: internals@lists.php.net
References: <CAA69SC5w-0KAGcX_akmhtFJL=mte+3ZrShKPtnWgcML+z-HhKw@mail.gmail.com>
 <CABdc3WqGFyM23CNA0eaMAyCn8L0=TaUf3xSoBOsFY_Gz4Z5uGA@mail.gmail.com>
 <CABdc3WqdTOid2BTGfpyVmNAca_9roxxx6AaQhKUPSYownO8MsA@mail.gmail.com>
 <0800a5ca-3d14-c541-1a1a-2574ec802b8c@fleshgrinder.com>
 <83fa661e-2d3d-6548-a506-fb969be31c0e@garfieldtech.com>
 <CAA69SC4=BXomSjmwm_6AEQGWqQqDC9scCVfv0aDH_rXMdZwt2A@mail.gmail.com>
 <c179bdb7-8665-9998-6f4f-99bbbfd19131@fleshgrinder.com>
 <CABdc3Wq_zfifnU=Y7TY8AXakBNO_KyDxaMhk0+Kubao_wGXaTg@mail.gmail.com>
 <56acc1d9-f424-a460-59be-3a9a1a74b198@fleshgrinder.com>
 <e06a39a8-305a-2de1-a8a7-e249d8179b09@gmx.de>
 <CAA69SC7wzKc2djTX267gaVpKd5-28H_GwAq2UBpzpRrqUfjpKQ@mail.gmail.com>
 <CAA69SC4QHSPpTo69X8siUv9gNmWdkgiBoiFE9Dsv_7n+Hnkpmw@mail.gmail.com>
 <b5f4cdb7-ab12-e508-5e1d-03d55db4eca0@gmx.de>
 <95832b08-ee80-18c1-a3da-202eed51903e@fleshgrinder.com>
 <2c115733-8fe4-5230-a9ec-9d5f2cc2b810@garfieldtech.com>
 <d4ccd291-f866-d510-7bbd-a4c5cf1a49e3@fleshgrinder.com>
Message-ID: <b8fd4372-3b38-e537-bb4c-bb11d7a08103@garfieldtech.com>
Date: Mon, 12 Sep 2016 15:11:41 -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: <d4ccd291-f866-d510-7bbd-a4c5cf1a49e3@fleshgrinder.com>
Content-Type: text/plain; charset=utf-8; format=flowed
Content-Transfer-Encoding: 7bit
Subject: Re: [PHP-DEV] RFC - Immutable classes
From: larry@garfieldtech.com (Larry Garfield)

On 09/12/2016 11:40 AM, Fleshgrinder wrote:
> On 9/11/2016 10:04 PM, Larry Garfield wrote:
>> On 09/10/2016 05:55 AM, Fleshgrinder wrote:
>>> @Larry what do you think about the CoW proposal?
>> I'm afraid I got lost in the thread somewhere with the back and forth
>> about implementation details. Can you repost the current proposal, or
>> has the RFC page been updated with the latest CoW-based recommendation?
>>
>> --Larry Garfield
>>
> No worries, here is the original message of mine in response to you (but
> I guess that I did not include you in the recipients):
>
> https://marc.info/?l=php-internals&m=147318929726088&w=2
>

Ah, I did see that one, but there was a lot of discussion after it so I 
thought the idea evolved.  Response below based on skimming the 
responses after that as well...

It sounds like there's more that needs to go on, though.  It sounds like 
that thread is suggesting that $this in a method of an immutable object 
is always cloned, which seems excessive to me.

The point about identity is well-taken.  However, it's more complex on 
objects because equality is not as simple as it is on strings. Two 
objects can be logically identical but physically different. For instance:

class HttpHeaders {
   public $attributes = [];
}

$a = new HttpHeaders();
$a->attributes['foo'] = 'bar';
$a->attributes['baz'] = 'buzz';

$b = new HttpHeaders();
$b->attributes['baz'] = 'buzz';
$b->attributes['foo'] = 'bar';

$a and $b are now not physically identical,  since their attributes 
array is in a different order.  However, header order doesn't matter in 
HTTP, or rather isn't supposed to.  (Modulo buggy implementations, of 
course.)  So are $a and $b identical?  I could very easily argue both 
directions on that.  Physical identity would be easier to automate 
checking in the engine; logical identity would require user-space code 
to make such decisions.

 From the discussion of "transformer" methods, I'd propose a slightly 
different keyword.  To wit:

1) A class marked as "immutable" may not have any of its properties 
altered, EXCEPT in certain unlocked scopes.  The constructor is an 
unlocked scope.

2) A method may be marked "clone": public clone function foo() {}. A 
clone method is identical to any other method except that A) $this in 
its scope is not the original object, but the result of clone($this); B) 
A clone method is an unlocked scope, so modifying $this (the clone) is 
legal.  That is more self-descriptive than "transformer", and also 
doesn't require a new keyword.  (By implication, clone and static are 
mutually exclusive since clone requires an object to clone.)

I don't know that there are any other unlocked scopes to consider...

#2 does leave us with the identity question that Richard raises, in that 
returning an unmodified $this from a clone method still creates a new 
object identity.  However, I posit that is to be expected.  In Python, 
eg, while some built-in objects are immutable they are not, necessarily, 
always the same physical object in memory.  (999+1 is not the same 
object as 1000, but 1+2 and 2 likely will be due to internal engine 
optimizations.)  You need to do a value comparison of them.

I don't see the identity case being resolved without an __identity() 
method, or similar.  Which could be useful in its own right so I'm not 
necessarily against it, but it's an extra, and I'd argue optional, piece 
of the puzzle.

Related to whether or not the properties of an object may be mutable 
(arrays, other objects, etc.), they would in practice probably need to 
blacklist resources.  We ran into that issue in PSR-7, where the body 
stream has to be mutable, because streams.  Since PSR-7 is based on PHP 
5.3 that doesn't cause any syntactic issues, just logical issues.  If 
the classes were marked immutable explicitly, it likely would be a 
problem since the streams cannot be immutable, thus they can't be used 
on an immutable object.  Which is... very sad making. :-(

--Larry Garfield