Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:122620 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 4F8151AD8F6 for ; Tue, 12 Mar 2024 07:20:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1710228044; bh=ax8QYBAiyXXr0tz9RqH3rlOTfgnSkmZQXQDyJIcoAiw=; h=In-Reply-To:References:Date:From:To:Cc:Subject:From; b=ORgK8AWXD9GRrNYudIrTEOzFSV1TCsklXmDWe+HPgmuIFBumaAqRl4D4hnvX+MG8t /soZTbO5eWv5L744NZo55oPHN9Ex/UYwMQC4MJWLfq2cYxjo9U4d6ctTmR9f9klaxY rLqXBXuCrg4Uo0JkKFBI0r1hfkg2bvo+PNpSZLPlUg8ZlcXWL7oS0xfZpcxG6ewlpk 0RAkeFygRc63AOhQ1J1MAKu1j+32NdOid3qM2UAlLL5ue18kFNCa7FyWT0nqR54xkm vFmUujLyP1dUOBMJqiETItl10d/toibZ1co5umlVSppMdV3xdX3gATxGCeQI4rMpP1 ibKdTW/GxOsQw== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 770F718006C for ; Tue, 12 Mar 2024 07:20:42 +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_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=no autolearn_force=no version=4.0.0 X-Spam-Virus: No X-Envelope-From: Received: from fhigh2-smtp.messagingengine.com (fhigh2-smtp.messagingengine.com [103.168.172.153]) (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 ; Tue, 12 Mar 2024 07:20:41 +0000 (UTC) Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) by mailfhigh.nyi.internal (Postfix) with ESMTP id F0CB5114013C; Tue, 12 Mar 2024 03:20:24 -0400 (EDT) Received: from imap49 ([10.202.2.99]) by compute1.internal (MEProxy); Tue, 12 Mar 2024 03:20:24 -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=fm2; t=1710228024; x= 1710314424; bh=ax8QYBAiyXXr0tz9RqH3rlOTfgnSkmZQXQDyJIcoAiw=; b=n tpAGc54WMRxDMSR6uJNXgXrqKu+acn+wvgharCNSekl5b38sSkbH1UfCX7Ozq8mB ynbM1M7wlf9z42GVwvwAvT2NGo22YefeX33HvBRqzNa9j/6Z1c9P7VEMYpiujlCt cDMy/3FH0czD1+m1pV5Olxd55gQwoIe/cgqP0N50pMi90qg9FE5hSoudGz8jH8yk uHwHEQbsyMOaJTmtxGuZ0EA+eDkrQZcrqWuvsfJggB+BR2+bPwUCwJXXvX2vC9m0 XjOnfnLrn6bJbxqonF3jf/xIyedXn7lGHo4WzlugXOecannGTbU5390ruJQ/Ktub Ac/3QeqT5ibLwyHggvD+g== 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= fm1; t=1710228024; x=1710314424; bh=ax8QYBAiyXXr0tz9RqH3rlOTfgnS kmZQXQDyJIcoAiw=; b=Atfp7D782bZ6yaB8j6sayTnIedHVbc/twRxeibbaCn5q U6SRULi3Du7gGpwdJUbndP5rfbPA2r2GDuTKyx3QjSVXNhFbTj+Zcko2vQQzzaHU lAhjHurwkHsLFcIg5Wwu3U16sddeC59Qtl6t1Bvsu3iokeXwIOSPPAKqnGXQbVl2 Qb2ruQQT5iAe6eK7zODlH3fBFFbYI1SYyiROe9VQYeAmEkz00skSckQWVaCbb3ib kX+f5I/APx/0nC/UqHgwAzghK9/ImKmyl6kUSsUEPCNekWb12k8BWTfqr1fh7i2m 4KJVjK4b/QH07XrGtDBQbc/7elgNJ0Rp5t2L+O77cQ== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvledrjedvgddutdejucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne goufhushhpvggtthffohhmrghinhculdegledmnecujfgurhepofgfggfkjghffffhvfev ufgtsegrtderreerreejnecuhfhrohhmpedftfhosgcunfgrnhguvghrshdfuceorhhosg essghothhtlhgvugdrtghouggvsheqnecuggftrfgrthhtvghrnhepuddvveegjeethfel iefhtedvleegvdeljeetueefudfhueevheelfeeljeejiefhnecuffhomhgrihhnpeefvh eglhdrohhrghenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhr ohhmpehrohgssegsohhtthhlvggurdgtohguvghs X-ME-Proxy: Feedback-ID: ifab94697:Fastmail Received: by mailuser.nyi.internal (Postfix, from userid 501) id 58B9D15A0092; Tue, 12 Mar 2024 03:20:24 -0400 (EDT) X-Mailer: MessagingEngine.com Webmail Interface User-Agent: Cyrus-JMAP/3.11.0-alpha0-251-g8332da0bf6-fm-20240305.001-g8332da0b Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net MIME-Version: 1.0 Message-ID: <0cce4ac2-b50f-420e-aa7e-7705f0c61629@app.fastmail.com> In-Reply-To: References: <1MzJ8G_MuG-LJsMSoGDIRBmSODjO4hxPACqMoQYfx83MS-du6sskpNLJ45HnzPYMoUNkXyGiZEUAtFk-uyeGDv_Kwg6Qgtod05pXCQH-8M8=@gpb.moe> Date: Tue, 12 Mar 2024 08:19:16 +0100 To: "Gina P. Banyard" , "Larry Garfield" Cc: "php internals" Subject: Re: [PHP-DEV] [Pre-RFC] Improve language coherence for the behaviour of offsets and containers Content-Type: multipart/alternative; boundary=00d33a1a3fc84430a6ab884adc331813 From: rob@bottled.codes ("Rob Landers") --00d33a1a3fc84430a6ab884adc331813 Content-Type: text/plain;charset=utf-8 Content-Transfer-Encoding: quoted-printable On Tue, Mar 12, 2024, at 02:36, Gina P. Banyard wrote: > On Monday, 11 March 2024 at 16:11, Larry Garfield wrote: >=20 > >=20 > > Woof. That's my kind of RFC. :-) The extensive background helps a lo= t, thank you. > >=20 > > I am generally in favor of this, and have wanted more fine-grained A= rrayAccess interfaces for a long time. > >=20 > > Thoughts in no particular order: > >=20 > > * "Dimension" is clearly based on the existing engine hooks, but as = a user-space dev, it's a very confusing term. Possibly documentable if t= here's an obvious logic for it we could present, but something more self= -evident is probably better. >=20 > I am open to naming changes, but "dimension" is very much the standard= and ubiquitous term for this, see multidimensional arrays, n-dimensiona= l array, etc. >=20 > >=20 > > * I am not sure combining get and exists into a single interface is = right. I'm not certain it's wrong, either, though. What is the argument = for combining them? > >=20 > > * Do we have some guidance for what offsetGet() should do when offse= tExists() is false? I know there isn't really any now, but it seems like= the sort of thing to think about here. >=20 > I will answer both points together. > The reason that checking an offset exists is combined with being able = to read it is that it just makes sense to be together. > If not and only the "read" operation is supported, how do you know tha= t an offset actually exists before accessing it? You just access it and = get an Exception that you need to catch? > It is also required for the null coalesce operator to function properl= y. >=20 > What offsetGet() does if the offset doesn't exist is up to the impleme= ntation, you could return null as a default value or throw an exception. > The only expectation is that *if* the offset exists, then reading the = value should be possible. >=20 > If you can only write to a container, then being able to check somethi= ng exists is somewhat meaningless. >=20 >=20 > >=20 > > * You sort of skirt around but don't directly address the impact of = this change on the long-standing desire to make array functions accept a= rrayified objects. What if any impact would this have there? Eg, could s= ome array functions be made to accept array|DimensionRead without breaki= ng the world? > >=20 > > * How, if at all, does this relate to iterable? I think it has no im= pact, but since it's in the same problem space it's worth confirming. >=20 > The former is actually also more related to iterable, as most array fu= nctions need to be able to traverse the container to be able to do anyth= ing meaningful with it. > Or there would need to be a way to provide a "manifest" of what offset= s are set for things like array_search or array_flip. >=20 > >=20 > > * You mention at one point applying shim code ArrayAccess to make it= work like the new interfaces. Please expand on that. Do you mean the en= gine would automatically insert some shims, like how `__toString()` now = magically implies `implements Stringable`? Or some trait that objects co= uld use (either a user-space trait or an engine trait) that would provid= e such shims in an overridable fashion? I don't fully follow here. > >=20 > > * If I read correctly, an internal object that implements one of the= dimension handlers will automagically appear to user-land as having the= corresponding interface, much like `__toString()`/`Stringable`. Is that= correct? It seemed implied but not fully stated. If so, a brief code ex= ample would help to make it clear in such a long RFC. >=20 > Move around a later point to respond to them together. > Internal objects don't actually magically implement Stringable, this i= s something internal objects must do themselves. > Moreover, internals objects can support string casts without implement= ing __toString(), see the GMP object which is the only example of this i= n php-src (and I should fix this or if someone else wants an easy PR to = do feel free). >=20 > To understand how the shim works, I first need to explain how interfac= es being implemented in a class work. >=20 > Internal interfaces can have a special handler called interface_gets_i= mplemented which gets called during compilation of classes. > This is the mechanism used by the Throwable and the DateTimeInterface = interfaces to prevent userland classes from implementing them. > The ArrayAccess interface has (and all the other Dimension ones actual= ly have) such a handler, and the "shim" is to set the append, fetch, and= fetch-append dimension handlers on the CE to magically support those op= erations on the class for the time being. > No methods are created on the class, the new interfaces are not implem= ented. > To override the behaviour of append/fetch/fetch-append the relevant ne= w interface should be implemented. >=20 > This is conceived as a temporary measure to ease migration for userlan= d classes that support those operations already. >=20 >=20 > >=20 > > * Big +1 to removing the magic semi-silent casting when using weird = key types. > >=20 > > * I feel like some of the sections could benefit from more short cod= e examples. Eg, What the heck does fetch-append on a null even look like= ? That would help illustrate why the current behavior is weird, or why s= ome things need to stay non-obvious because they're used in odd cases. (= Like how $a[1][2] is a by-ref fetch internally, something most people do= n't think about.) > >=20 >=20 > I find having too many examples makes RFCs difficult to read and parse= , and I prefer to use them sparingly for when they are really needed. > Just for clarity but $a[1][2] is only a by-ref fetch for write operati= ons, if it is a read operation those are performed in sequence. > Fetch-append on null is not really weird, it just appends the given va= lue (/null if no assignments happens) and provides a reference to it. > See https://3v4l.org/UPg3P For what it=E2=80=99s worth, I think having some short one-liner example= s sprinkled throughout the RFC is a good thing here. I had to constantly= scroll back up to remind myself what each operation actually was in cod= e.=20 There are a lot of familiar concepts, just with new and particular langu= age; having examples along the way to remind the reader what this new la= nguage resolves to would help, not hinder.=20 =E2=80=94 Rob --00d33a1a3fc84430a6ab884adc331813 Content-Type: text/html;charset=utf-8 Content-Transfer-Encoding: quoted-printable

=
On Tue, Mar 12, 2024, at 02:36, Gina P. Banyard wrote:
On Monday, 11= March 2024 at 16:11, Larry Garfield <larry@garfieldtech.com> wrote:


> Woof. That's my kind of RFC. :-) The= extensive background helps a lot, thank you.
> I am generally in favor of this, and have wanted more = fine-grained ArrayAccess interfaces for a long time.
>&= nbsp;
> Thoughts in no particular order:
= > 
> * "Dimension" is clearly based on the exis= ting engine hooks, but as a user-space dev, it's a very confusing term. = Possibly documentable if there's an obvious logic for it we could presen= t, but something more self-evident is probably better.
I am open to naming changes, but "dimension" is very much th= e standard and ubiquitous term for this, see multidimensional arrays, n-= dimensional array, etc.


> * I am not sure combining get and exists into a single interf= ace is right. I'm not certain it's wrong, either, though. What is the ar= gument for combining them?

> *= Do we have some guidance for what offsetGet() should do when offsetExis= ts() is false? I know there isn't really any now, but it seems like the = sort of thing to think about here.

I will a= nswer both points together.
The reason that checking an of= fset exists is combined with being able to read it is that it just makes= sense to be together.
If not and only the "read" operatio= n is supported, how do you know that an offset actually exists before ac= cessing it? You just access it and get an Exception that you need to cat= ch?
It is also required for the null coalesce operator to = function properly.

What offsetGet() does if= the offset doesn't exist is up to the implementation, you could return = null as a default value or throw an exception.
The only ex= pectation is that *if* the offset exists, then reading the value should = be possible.

If you can only write to a con= tainer, then being able to check something exists is somewhat meaningles= s.



= > * You sort of skirt around but don't directly address the impact of= this change on the long-standing desire to make array functions accept = arrayified objects. What if any impact would this have there? Eg, could = some array functions be made to accept array|DimensionRead without break= ing the world?

> * How, if at = all, does this relate to iterable? I think it has no impact, but since i= t's in the same problem space it's worth confirming.

<= /div>
The former is actually also more related to iterable, as most = array functions need to be able to traverse the container to be able to = do anything meaningful with it.
Or there would need to be = a way to provide a "manifest" of what offsets are set for things like ar= ray_search or array_flip.


> * You mention at one point applying shim code ArrayAccess t= o make it work like the new interfaces. Please expand on that. Do you me= an the engine would automatically insert some shims, like how `__toStrin= g()` now magically implies `implements Stringable`? Or some trait that o= bjects could use (either a user-space trait or an engine trait) that wou= ld provide such shims in an overridable fashion? I don't fully follow he= re.

> * If I read correctly, a= n internal object that implements one of the dimension handlers will aut= omagically appear to user-land as having the corresponding interface, mu= ch like `__toString()`/`Stringable`. Is that correct? It seemed implied = but not fully stated. If so, a brief code example would help to make it = clear in such a long RFC.

Move around a lat= er point to respond to them together.
Internal objects don= 't actually magically implement Stringable, this is something internal o= bjects must do themselves.
Moreover, internals objects can= support string casts without implementing __toString(), see the GMP obj= ect which is the only example of this in php-src (and I should fix this = or if someone else wants an easy PR to do feel free).

=
To understand how the shim works, I first need to explain how= interfaces being implemented in a class work.

<= div>Internal interfaces can have a special handler called interface_gets= _implemented which gets called during compilation of classes.
<= div>This is the mechanism used by the Throwable and the DateTimeInterfac= e interfaces to prevent userland classes from implementing them.
The ArrayAccess interface has (and all the other Dimension ones a= ctually have) such a handler, and the "shim" is to set the append, fetch= , and fetch-append dimension handlers on the CE to magically support tho= se operations on the class for the time being.
No methods = are created on the class, the new interfaces are not implemented.
To override the behaviour of append/fetch/fetch-append the relev= ant new interface should be implemented.

Th= is is conceived as a temporary measure to ease migration for userland cl= asses that support those operations already.



> * Big +1 to removing the = magic semi-silent casting when using weird key types.
>=  
> * I feel like some of the sections could benef= it from more short code examples. Eg, What the heck does fetch-append on= a null even look like? That would help illustrate why the current behav= ior is weird, or why some things need to stay non-obvious because they'r= e used in odd cases. (Like how $a[1][2] is a by-ref fetch internally, so= mething most people don't think about.)


I find having too many examples makes RFCs difficu= lt to read and parse, and I prefer to use them sparingly for when they a= re really needed.
Just for clarity but $a[1][2] is only a = by-ref fetch for write operations, if it is a read operation those are p= erformed in sequence.
Fetch-append on null is not really w= eird, it just appends the given value (/null if no assignments happens) = and provides a reference to it.
=
For what it=E2=80=99s worth, I think having some short on= e-liner examples sprinkled throughout the RFC is a good thing here. I ha= d to constantly scroll back up to remind myself what each operation actu= ally was in code.

There are a lot of famil= iar concepts, just with new and particular language; having examples alo= ng the way to remind the reader what this new language resolves to would= help, not hinder. 

=E2=80=94 Rob
--00d33a1a3fc84430a6ab884adc331813--