Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:124403 X-Original-To: internals@lists.php.net Delivered-To: internals@lists.php.net Received: from php-smtp4.php.net (php-smtp4.php.net [45.112.84.5]) by qa.php.net (Postfix) with ESMTPS id 459D61A00B7 for ; Fri, 12 Jul 2024 06:47:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1720766963; bh=4CmRRWxL0a9i6jO14artD4vHjZB8TogepHl31Iyu2dc=; h=In-Reply-To:References:Date:From:To:Cc:Subject:From; b=aldXw49G2BZtI5jjMEiry2iqowHuSxuFJzs923HQ6jlKg2vGviBGTDJAnF84ps4Qw bUxcG4QKrOjDIhDoUhCH8ULNV97kvZIaX8g7kI126mJ7wPPsePtP+pyAu5OBsfHveN nceD2hl7jatrntb6Occ/MAiMSJI+vc8+ZbrL+Tp1Cs0/dF6dmLwc9tRyJTYGH/4bwO G1ut9q1bgh3F2wvwERAKsuHPdPDGPM420sh5vAERyBcyd5leg2vUzktnemz3n9nBp4 H/hoVSNp4SyK6wcxZLfwN14XAQU45qs27L1E74YsoHs7YylCNnNytxcMAgK0a1c4XN ap2z6wfAATAVw== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 3217E18067A for ; Fri, 12 Jul 2024 06:49:23 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.0 (2022-12-13) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=-0.1 required=5.0 tests=BAYES_50,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_MISSING,HTML_MESSAGE, RCVD_IN_DNSWL_LOW,SPF_HELO_PASS,SPF_PASS autolearn=no autolearn_force=no version=4.0.0 X-Spam-Virus: No X-Envelope-From: Received: from fout1-smtp.messagingengine.com (fout1-smtp.messagingengine.com [103.168.172.144]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Fri, 12 Jul 2024 06:49:22 +0000 (UTC) Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) by mailfout.nyi.internal (Postfix) with ESMTP id 278811388786; Fri, 12 Jul 2024 02:47:55 -0400 (EDT) Received: from imap49 ([10.202.2.99]) by compute1.internal (MEProxy); Fri, 12 Jul 2024 02:47:55 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bottled.codes; h=cc:cc:content-type:content-type:date:date:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to; s=fm3; t=1720766875; x= 1720853275; bh=s9MAIWV/gr2LNInldc25/y/dZcHmi7Nm101h+/siXt4=; b=F 27AheDe2F228maR28NJ1UlxwB1LHCqtJ0JRkO1SiiAaKgJ9L/kKtnfmY70VYPIFe HfNYStJxfpCQ1xq1XDsKq4baNjQQCpx+UHOK4C+Oh/GiqaUrsRtuvOabWHKFRsyp 2K6cAPjcyLmEiSE+6b7fblSwfCwDg8O3J11BYUjhoAvoPmIrjeG86ubY8OJUhYE5 sBk0haLTDwCFAEKCukQracVFzl25PeSRR1VxZ8eT0M6z5sz8vngZ82Clq/izKgDL a8WhHF9PfG18vZO1e/1tdNpqD+9DKb5Zci2cPXL0p1uXJKlHfjb2WOM+Bhi8tup3 MSMc7ZiltQl0H2eHZLmIw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm2; t=1720766875; x=1720853275; bh=s9MAIWV/gr2LNInldc25/y/dZcHm i7Nm101h+/siXt4=; b=S3ValtAzb4mvp6ybQPKaxGdLIJ9EQiIe59hNm6T4rqku FwXAg97GqCsdwNoqpwJ7f6yr3WTdOYTK4sylfEzjAhO2GEF3tcEFBdKzUcOsFw5A 2RS/s35HjBSSqEfpUquOg3xPg6I66IdTMz+RZH57YPXIy/KXHgC7N+JoZv6MJdUk qBrmvzwXnNXS+WEWSAXIzgsZvYTrCBiwEq5rr85w+7cWjkrupfMLench+Cby1qS2 DKIguIB2C3/IXDuGWS1WO+qPAxBpIFLNTXDyxNYbXrPVbMTm7cXu7lpIphvsHnD+ twoNltmu6uIPPbWaH4gBDTLCYcMytsRekr/zZ8nHMw== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeftddrfeehgdduudefucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepofgfggfkjghffffhvfevufgtsegrtderreerreejnecuhfhrohhmpedftfho sgcunfgrnhguvghrshdfuceorhhosgessghothhtlhgvugdrtghouggvsheqnecuggftrf grthhtvghrnhepvdehkeetleevteefveegkefgffdvuefhleevhedvteeigfegtdefjeeh tefghfeunecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomh eprhhosgessghothhtlhgvugdrtghouggvsh X-ME-Proxy: Feedback-ID: ifab94697:Fastmail Received: by mailuser.nyi.internal (Postfix, from userid 501) id 9D35C15A0092; Fri, 12 Jul 2024 02:47:54 -0400 (EDT) X-Mailer: MessagingEngine.com Webmail Interface User-Agent: Cyrus-JMAP/3.11.0-alpha0-568-g843fbadbe-fm-20240701.003-g843fbadb Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net MIME-Version: 1.0 Message-ID: <040d363e-4e56-408b-b066-928eac82b9c4@app.fastmail.com> In-Reply-To: <61ab36bc-b045-452a-84e0-87367d4c680e@bastelstu.be> References: <1118bbcd-a7b4-47bf-bf35-1a36ab4628e1@bastelstu.be> <45847b93-02bf-459f-bcd2-81ba35a12c24@bastelstu.be> <46bd4098-2936-4e46-98e9-fe55118325c2@bastelstu.be> <61ab36bc-b045-452a-84e0-87367d4c680e@bastelstu.be> Date: Fri, 12 Jul 2024 08:47:33 +0200 To: =?UTF-8?Q?Tim_D=C3=BCsterhus?= , "Nicolas Grekas" Cc: "PHP Internals List" Subject: Re: [PHP-DEV] [RFC] Lazy Objects Content-Type: multipart/alternative; boundary=67af082e0125474b9ec9e48adaa70bea From: rob@bottled.codes ("Rob Landers") --67af082e0125474b9ec9e48adaa70bea Content-Type: text/plain;charset=utf-8 Content-Transfer-Encoding: quoted-printable On Thu, Jul 11, 2024, at 20:31, Tim D=C3=BCsterhus wrote: > Hi >=20 > On 7/11/24 10:32, Nicolas Grekas wrote: ... snip > > The $originalProxy is *not* shared with $clonedProxy. Instead, it's > > *initializers* that are shared between clones. > > And then, when we call that shared initializer in the $clonedProxy, = we > > clone the returned instance, so that even if the initializer returns= a > > shared instance, we don't share anything with the $originalProxy. > >=20 >=20 > Ah, so you mean if the initializer would look like this instead of=20 > creating a fresh object within the initializer? >=20 > $predefinedObject =3D new SomeObj(); > $myProxy =3D $r->newLazyProxy(function () use ($predefinedObject= ) { > return $predefinedObject; > }); > $clonedProxy =3D clone $myProxy; > $r->initialize($myProxy); > $r->initialize($clonedProxy); >=20 > It didn't even occur to me that one would be able to return a=20 > pre-existing object: I assume that simply reusing the initializer woul= d=20 > create a separate object and that would be sufficient to ensure that t= he=20 > cloned instance would be independent. >=20 > >=20 > >> ? Then I believe this is unsound. Consider the following: > >> > >> $myProxy =3D $r->newLazyProxy(...); > >> $clonedProxy =3D clone $myProxy; > >> $r->initialize($myProxy); > >> $myProxy->someProp++; > >> var_dump($clonedProxy->someProp); > >> > >> The clone was created before `someProp` was modified, but it output= s the > >> value after modification! > >> > >> Also: What happens if the cloned proxy is initialized *before* the > >> original proxy? There is no real object to clone. > >> > >> I believe the correct behavior would be: Just clone the proxy and k= eep > >> the same initializer. Then both proxies are actually fully independ= ent > >> after cloning, as I would expect from the clone operation. > >> > >=20 > > That's basically what we do and what we describe in the RFC, just wi= th the > > added lazy-clone operation on the instance returned by the initializ= er. > >=20 >=20 > This means that if I would return a completely new object within the=20 > initializer then for a cloned proxy the new object would immediately b= e=20 > cloned and the original object be destructed, yes? >=20 > Frankly, thinking about this cloning behavior gives me a headache,=20 > because it quickly leads to very weird semantics. Consider the followi= ng=20 > example: >=20 > $predefinedObject =3D new SomeObj(); > $initializer =3D function () use ($predefinedObject) { > return $predefinedObject; > }; > $myProxy =3D $r->newLazyProxy($initializer); > $otherProxy =3D $r->newLazyProxy($initializer); > $clonedProxy =3D clone $myProxy; > $r->initialize($myProxy); > $r->initialize($otherProxy); > $r->initialize($clonedProxy); >=20 > To my understanding both $myProxy and $otherProxy would share the=20 > $predefinedObject as the real instance and $clonedProxy would have a=20 > clone of the $predefinedObject at the time of the initialization as it= s=20 > real instance? >=20 > To me this sounds like cloning an uninitialized proxy would need to=20 > trigger an initialization to result in semantics that do not violate t= he=20 > principle of least astonishment. I think it would be up to the developer writing the proxy framework to u= se or abuse this, for example, I've been trying for years to get some de= cent semantics of value objects in PHP (I may or may not create an RFC f= or it once I've finished all my research), but, this seems like a perfec= tly usable case that creates the principle of least astonishment for val= ue objects. For example, if you have an immutable Money(10) and clone Mo= ney(10) .... is there any reason to create a new Money(10)? Currently, c= lone's default behavior is already astonishing for value objects! The in= stance doesn't matter; it's the value that matters. For service objects,= it may be the same thing -- at least, IMHO, services shouldn't have sta= te, just behavior. For non-value objects, such as those in the domain, m= aybe they should be fetched anew from the DB, created newly from a cache= , or cloned from an existing instance. The point is, that this can have framework-level behavior that simply is= n't possible right now because there is no way to control a clone operat= ion properly. I'm actually quite excited to have some more control over = cloning (even in this limited form) because the current behavior of __cl= one is so cobbled that it is barely usable except for the most basic of = programs, and currently, the only solution is to disable cloning when it= will break assumptions. =E2=80=94 Rob --67af082e0125474b9ec9e48adaa70bea Content-Type: text/html;charset=utf-8 Content-Transfer-Encoding: quoted-printable
On Thu, Jul 11,= 2024, at 20:31, Tim D=C3=BCsterhus wrote:
Hi

On 7/11/= 24 10:32, Nicolas Grekas wrote:

... snip

> The $originalProxy is *not* shared with $clonedProxy. In= stead, it's
> *initializers* that are shared between cl= ones.
> And then, when we call that shared initializer = in the $clonedProxy, we
> clone the returned instance, = so that even if the initializer returns a
> shared inst= ance, we don't share anything with the $originalProxy.
>= ; 

Ah, so you mean if the initializer = would look like this instead of 
creating a fresh obj= ect within the initializer?

  &nb= sp;   $predefinedObject =3D new SomeObj();
 = ;     $myProxy =3D $r->newLazyProxy(function () u= se ($predefinedObject) {
     &nb= sp;    return $predefinedObject;
 &nbs= p;    });
      $c= lonedProxy =3D clone $myProxy;
    &nb= sp; $r->initialize($myProxy);
    &= nbsp; $r->initialize($clonedProxy);

It d= idn't even occur to me that one would be able to return a 
pre-existing object: I assume that simply reusing the initializer = would 
create a separate object and that would be suf= ficient to ensure that the 
cloned instance would be = independent.


>&= gt; ? Then I believe this is unsound. Consider the following:
<= div>>>
>>       = $myProxy =3D $r->newLazyProxy(...);
>>  = ;     $clonedProxy =3D clone $myProxy;
>>       $r->initialize($myProxy= );
>>       $myProxy-&= gt;someProp++;
>>      = ; var_dump($clonedProxy->someProp);
>>
<= div>>> The clone was created before `someProp` was modified, but i= t outputs the
>> value after modification!
=
>>
>> Also: What happens if the cloned pr= oxy is initialized *before* the
>> original proxy? T= here is no real object to clone.
>>
&g= t;> I believe the correct behavior would be: Just clone the proxy and= keep
>> the same initializer. Then both proxies are= actually fully independent
>> after cloning, as I w= ould expect from the clone operation.
>>

> That's basically what we do and what we= describe in the RFC, just with the
> added lazy-clone = operation on the instance returned by the initializer.
>= ; 

This means that if I would return a= completely new object within the 
initializer then f= or a cloned proxy the new object would immediately be 
cloned and the original object be destructed, yes?

<= /div>
Frankly, thinking about this cloning behavior gives me a heada= che, 
because it quickly leads to very weird semantic= s. Consider the following 
example:
      $predefinedObject =3D new Som= eObj();
      $initializer =3D fu= nction () use ($predefinedObject) {
   &nbs= p;      return $predefinedObject;
      };
    = ;  $myProxy =3D $r->newLazyProxy($initializer);
&n= bsp;     $otherProxy =3D $r->newLazyProxy($initia= lizer);
      $clonedProxy =3D cl= one $myProxy;
      $r->initia= lize($myProxy);
      $r->init= ialize($otherProxy);
      $r->= ;initialize($clonedProxy);

To my understand= ing both $myProxy and $otherProxy would share the 
$p= redefinedObject as the real instance and $clonedProxy would have a =
clone of the $predefinedObject at the time of the initial= ization as its 
real instance?

To me this sounds like cloning an uninitialized proxy would need = to 
trigger an initialization to result in semantics = that do not violate the 
principle of least astonishm= ent.

I think it would be up to= the developer writing the proxy framework to use or abuse this, for exa= mple, I've been trying for years to get some decent semantics of value o= bjects in PHP (I may or may not create an RFC for it once I've finished = all my research), but, this seems like a perfectly usable case that crea= tes the principle of least astonishment for value objects. For example, = if you have an immutable Money(10) and clone Money(10) .... is there any= reason to create a new Money(10)? Currently, clone's default behavior i= s already astonishing for value objects! The instance doesn't matter; it= 's the value that matters. For service objects, it may be the same thing= -- at least, IMHO, services shouldn't have state, just behavior. For no= n-value objects, such as those in the domain, maybe they should be fetch= ed anew from the DB, created newly from a cache, or cloned from an exist= ing instance.

The point is, that this can h= ave framework-level behavior that simply isn't possible right now becaus= e there is no way to control a clone operation properly. I'm actually qu= ite excited to have some more control over cloning (even in this limited= form) because the current behavior of __clone is so cobbled that it is = barely usable except for the most basic of programs, and currently, the = only solution is to disable cloning when it will break assumptions.
<= /div>

=E2=80=94 Rob
--67af082e0125474b9ec9e48adaa70bea--