Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:126868 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 1903F1A00BC for ; Thu, 20 Mar 2025 16:16:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1742487245; bh=lV5VE+LkuFSOl8fXJPalPmPUlOEuB5QvJpM3Ibm/eo8=; h=Date:From:To:Cc:In-Reply-To:References:Subject:From; b=LP/HOOB+g9TrjpPslCyjym94fkZm0ceWc1OIiQZWAdlx3Oe4sNDC2UkqQVR6z8spK QPlm59fAtmnb+tNPUBCJTNb2kj2YIWbUTWjrYomBE0GHn7iIPtyxQ8FV1w45SayTvs j4xvyaGJm25Vnoz/nncIEE/lU6f8is4dkrF9BMn1sIsHYssLCiGCPix6W7qnt/p2Ru Q2w7Wm2AVjVKdYfQ9Ji/+wyG/x9e5bu9QXw8eIcWUIWhjHfCGM8GRQcqsjHGetguIG IPIb6zqx57EiylLY7B/Cddyg7HFidA8TBw1KWc92zHcU8cvqQifjeqLwkU443LVhg1 RJ2/nQ0D2MPOg== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id E6A4918007E for ; Thu, 20 Mar 2025 16:14:03 +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=-2.8 required=5.0 tests=BAYES_00,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 fout-b1-smtp.messagingengine.com (fout-b1-smtp.messagingengine.com [202.12.124.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 ; Thu, 20 Mar 2025 16:14:03 +0000 (UTC) Received: from phl-compute-11.internal (phl-compute-11.phl.internal [10.202.2.51]) by mailfout.stl.internal (Postfix) with ESMTP id AC290114019E; Thu, 20 Mar 2025 12:16:33 -0400 (EDT) Received: from phl-imap-09 ([10.202.2.99]) by phl-compute-11.internal (MEProxy); Thu, 20 Mar 2025 12:16:33 -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=1742487393; x= 1742573793; bh=2z8jj11lWVUWpHz0ja6FsR4DOVRu9p5xNa7fMV1++5s=; b=Y rAQ0CpImjg5lhmjKdu7jc26Cm5zK48X9MCDV6IhnkLiL+JeglGMIbbmTY27xTXBS 99ysDT+vczGQNAvjHy78PdjoeW6B+An17TRWfcW58uuRN9wh9OimfFUgWKRGYKxi eSEow5+wf1pvMJCUZizKQEmrMJlwJHyt7hWLuiVQLEWmPKG3DEXpnq5MmO5+lNUQ 0Er/ckE2qxX/A9iay3suvC3caMiTt6zgrweP3NNCPWL9Z7sbyXiQeJ3Y1t4gd0PA aVOHtAJDQThyMfykiZiIoNJA1Nv5gGEf7TVQd0h2W73hs2Tn8cDDXL2NNfITlZP/ KgyN9o6W2d88HkmAev3pg== 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-sender:x-me-sender:x-sasl-enc; s=fm1; t= 1742487393; x=1742573793; bh=2z8jj11lWVUWpHz0ja6FsR4DOVRu9p5xNa7 fMV1++5s=; b=y5J6lio+GNP97DosGLRQRI0BxXGeIQwKgoJH3dUAPWKuoLHGECH aOuresMpTYlSQa2hxNkCCWDOITWWEYZAnud7OLogR5mWVJp/x4GxOuuurBfRlbE0 IxNMjjYpKaGQKWdYFPSFJi4kn1SQy4AvONVdAbkAIy6pPoGdNDqkmZqRmS0FuwhG FnfNoMGI/GC0wJA9ciKBK/9B1MRRttlZ0YIzuiSPKmG6cZ7ED1wiFSfLEIKbbrVU UysDp0ENQtHROJCHipfVkT4tVII7LRXcIh7oDQeyXZ8SDMLW6wQtjSUa1ChTTpVk 3PDUr8OYtICG4dtfm3LbU4feHAaomFeDd0Q== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefvddrtddtgddugeekieeiucetufdoteggodetrf dotffvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdggtfgfnhhsuhgsshgtrhhisggv pdfurfetoffkrfgpnffqhgenuceurghilhhouhhtmecufedttdenucesvcftvggtihhpih gvnhhtshculddquddttddmnecujfgurhepofggfffhvfevkfgjfhfutgesrgdtreerredt jeenucfhrhhomhepfdftohgsucfnrghnuggvrhhsfdcuoehrohgssegsohhtthhlvggurd gtohguvghsqeenucggtffrrghtthgvrhhnpeeiueethedvvdefjefhgfeiheelheehtdfh feekjefflefgvedvkeduteejjedttdenucevlhhushhtvghrufhiiigvpedtnecurfgrrh grmhepmhgrihhlfhhrohhmpehrohgssegsohhtthhlvggurdgtohguvghspdhnsggprhgt phhtthhopedvpdhmohguvgepshhmthhpohhuthdprhgtphhtthhopegsohgsfigvihelse hhohhtmhgrihhlrdgtohhmpdhrtghpthhtohepihhnthgvrhhnrghlsheslhhishhtshdr phhhphdrnhgvth X-ME-Proxy: Feedback-ID: ifab94697:Fastmail Received: by mailuser.phl.internal (Postfix, from userid 501) id 3137F780068; Thu, 20 Mar 2025 12:16:33 -0400 (EDT) X-Mailer: MessagingEngine.com Webmail Interface Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net x-ms-reactions: disallow MIME-Version: 1.0 X-ThreadId: Tb82dc1343eb6237f Date: Thu, 20 Mar 2025 17:16:12 +0100 To: "Bob Weinand" Cc: "internals@lists.php.net" Message-ID: <5b1e6d70-a1c9-455c-93d3-6b22cf1fef11@app.fastmail.com> In-Reply-To: References: <3e4ba7ea-a154-452d-abfc-05ef1322fade@app.fastmail.com> <782d76d9-711a-4cee-ae0e-fe0d69973f53@app.fastmail.com> <48dce917-d147-456b-9f03-c7e23411adff@app.fastmail.com> <8a16b81c-7dab-4523-a352-76ba0cb4e771@app.fastmail.com> <9c4ac301-dfb2-49da-90e5-37a2824fc4e3@app.fastmail.com> Subject: Re: [PHP-DEV] RFC: short and inner classes Content-Type: multipart/alternative; boundary=39c5f759b1c04975b53a2c870074b7d1 From: rob@bottled.codes ("Rob Landers") --39c5f759b1c04975b53a2c870074b7d1 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable On Thu, Mar 20, 2025, at 16:41, Bob Weinand wrote: >=20 >> Am 20.03.2025 um 16:28 schrieb Rob Landers : >> =EF=BB=BF >>=20 >>=20 >> On Thu, Mar 20, 2025, at 16:12, Bob Weinand wrote: >>>=20 >>>> Am 20.03.2025 um 15:51 schrieb Rob Landers : >>>> =EF=BB=BF >>>>=20 >>>>=20 >>>> On Wed, Mar 19, 2025, at 21:09, Bob Weinand wrote: >>>>>=20 >>>>>=20 >>>>> On 19.3.2025 16:04:06, Rob Landers wrote: >>>>>> On Tue, Mar 18, 2025, at 03:37, Bob Weinand wrote: >>>>>>> Okay, I see the point with LSP. I'm not sure whether we need to = preserve LSP for that specific scenario, but neither can I say that we s= hould ignore it. >>>>>>>=20 >>>>>>> (Effectively implementing LSP would mean that there's an implici= t interface matching all public method signatures of the parent class, f= or child classes - which is doable, but possibly too much for the initia= l RFC.) >>>>>>>=20 >>>>>>> I would however ask, should we not implement LSP compatible inne= r classes, to enforce that no child class may name a class the same than= any non-private inner class declared by any of its parents, until we re= solve this question (in possibly a future version of PHP). >>>>>>> I do not think we should bar ourselves from allowing this in the= future. >>>>>>=20 >>>>>> I'm not sure I understand what you are asking. But I think you ar= e saying the following should be illegal? >>>>>>=20 >>>>>> class ParentOuter { >>>>>> class ParentInner {} >>>>>> } >>>>>>=20 >>>>>> class ChildOuter extends ParentOuter { >>>>>> class ParentInner {} // not allowed >>>>>> } >>>>> Precisely. >>>>>=20 >>>>>>> And not pretending starts with using a different symbol than a b= ackslash. >>>>>>=20 >>>>>> I have been thinking about this for a couple of days now... When = thinking through the ramifications of my decision to use :> over ::, thi= s will also affect generics, most likely -- whenever that happens. This = is because if this RFC passes, generics will want to be consistent with = whatever exists currently. >>>>>>=20 >>>>>> If we were to use :>, then generics would probably look something= like this to be consistent: >>>>>>=20 >>>>>> class Box { >>>>>> public function add(self:>T $item) {} >>>>>> } >>>>>>=20 >>>>>> The same thing would also probably apply to :: >>>>>>=20 >>>>>> class Box { >>>>>> public function add(self::T $item) {} >>>>>> } >>>>>>=20 >>>>>> With `\`, it nearly follows exactly what you would expect-ish: >>>>>>=20 >>>>>> use \Box\T as T; >>>>>>=20 >>>>>> class Box { >>>>>> public function add(T $item) {} >>>>>>=20 >>>>>> // or without use >>>>>> public function add(Box\T $item) {} >>>>>> } >>>>>>=20 >>>>>> With `\`, we can also just automatically check the current class = as part of namespace resolution when compiling: >>>>>>=20 >>>>>> class Box { >>>>>> public function add(T $item) {} >>>>>> } >>>>>>=20 >>>>>> This would also make it easier to user inner classes: >>>>>>=20 >>>>>> class Outer { >>>>>> public class Inner {} >>>>>> public function foo(Inner $bar) {} >>>>>> } >>>>>>=20 >>>>>> The other syntax options do not allow this; at least, I don't thi= nk so. I'm very heavily leaning towards `\` as the separator. >>>>>>=20 >>>>>> =E2=80=94 Rob >>>>> I'm failing to understand why you'd think this would be related at= all? >>>>>=20 >>>>> If we get generics, >>>>>=20 >>>>> class Box { >>>>> public function add(T $item) {} >>>>> } >>>>>=20 >>>>> would just work, without any use or such. There will not be a symb= ol Box::T or Box\T, just all mentions of T within the Box class will be = taken as "this is the generic placeholder" and the compiler takes care. >>>>> It's not like that T will be directly accessible from outside of t= he class or actually a proper type, unlike inner classes. >>>>>=20 >>>>> A generic is not an inner class nor will it look like it. Also, th= ere's no accessing of a parents generic - you write class Child exten= ds ParentClass - or something along these lines, getting the T availa= ble for your class. >>>>>=20 >>>>> Bob >>>>=20 >>>> Yes, that is the question right? It might not affect anything there= , but there would probably be an argument to keep it consistent with inn= er classes. In PHP, a class is a type; thus an inner class is an inner t= ype, and generic types are also an inner type that only exist in the sco= pe of their enclosing class, just like private inner classes. >>>>=20 >>>> If my logic is incorrect, let me know. >>>>=20 >>>> =E2=80=94 Rob >>>=20 >>> The difference is that inner classes are a backed type; there's actu= ally a class/interface/enum/... behind it. >>>=20 >>> Generic placeholders are placeholders for another type, which is str= ictly local to the compilation of the class. >>>=20 >>> Bob >>=20 >> If that were the case, then this would be an error: >>=20 >> function add(T $item) { >> if ($item instanceof T) {} >> } >>=20 >> because T isn't a backed type. I don't think they are the same thing,= but during runtime, T is most definitely a backed-type; not an empty bo= x. You still have to refer to T in some way, and I'm of the opinion that= self:>T is not ideal (I think we can probably all agree on that?). Even= in inner classes, it seems to make more sense to just treat it like you= would any other type in the current namespace. >=20 > It's a *placeholder* for a backed type. > At runtime (or during monomorphization), the T will be replaced by the= actual type. >=20 > Whatever name T refers to is the actual backed type. >=20 > Bob Right, my point is that you have to refer to T in the first place. If we= use `\`, then T as-is is fine, because there is a clear resolution to w= hat T you are referring to. If we use :> or ::, then when you write Box<= T>, are you referring to T, as in the generic T; or T as in the class T = in the same namespace. This is clear when we use "T" literally, but quic= kly becomes not so clear when using something else: class Item {} class Box { public function add(Item $item) {} } This is exactly why I said this matters! In the case above with the curr= ent :> syntax, we should probably use: class Box { public function add(self:>Item $item) { } to explicitly define that we want the inner type "Item." To use the firs= t example, you have to define inner types to allow that, but we are curr= ently defining inner types in this RFC. I'd personally rather use the fi= rst example when it comes to generics, which means we need to define tha= t now. In other words, I think you are on team "\" without realizing you= are on team "\". =E2=80=94 Rob --39c5f759b1c04975b53a2c870074b7d1 Content-Type: text/html; charset=utf-8 Content-Transfer-Encoding: quoted-printable

=
On Thu, Mar 20, 2025, at 16:41, Bob Weinand wrote:

<= /div>
Am 20.03.2025 um 16= :28 schrieb Rob Landers <rob@bottled.codes>:
=EF=BB=BF


On Thu, Mar 20, 2025, at 16:12, Bob= Weinand wrote:

Am 20.03.2025 um 15:51 schrieb Rob Landers <rob@bottled.codes&g= t;:
=EF=BB=BF


On Wed, Ma= r 19, 2025, at 21:09, Bob Weinand wrote:


On 19.3.2025 16:04:06, Rob Landers wrote:
On Tue, Mar 18, 2025, at 03:37, Bob Weinand wrote:

Okay, I se= e the point with LSP. I'm not sure whether we need to preserve LSP for t= hat specific scenario, but neither can I say that we should ignore it.

(Effectively implementing LSP would mean that there's an implic= it interface matching all public method signatures of the parent class, = for child classes - which is doable, but possibly too much for the initi= al RFC.)

I would however ask, should we not implement LSP co= mpatible inner classes, to enforce that no child class may name a class = the same than any non-private inner class declared by any of its parents= , until we resolve this question (in possibly a future version=0A of PHP= ).
I do not think we should bar ourselves from allowing th= is in the future.

I'm not sure= I understand what you are asking. But I think you are saying the follow= ing should be illegal?

class ParentOuter {<= br>
  class ParentInner {}
}
=
class ChildOuter extends ParentOuter {
&nbs= p; class ParentInner {} // not allowed
}

Precisely.

And not pretending starts with using= a different symbol than a backslash.

I have been thinking about this for a couple of days now... When= thinking through the ramifications of my decision to use :> over ::,= this will also affect generics, most likely -- whenever that happens. T= his is because if this RFC passes, generics will=0A want to be consisten= t with whatever exists currently.

If we wer= e to use :>, then generics would probably look something like this to= be consistent:

class Box<T> {
  public function add(self:>T $item) {}
}<= br>

The same thing would also probably apply to= ::

class Box<T> {
&nbs= p; public function add(self::T $item) {}
}
<= br>
With `\`, it nearly follows exactly what you would expect-= ish:

use \Box\T as T;

class Box<T> {
  public function add(T = $item) {}

// or without use
&= nbsp; public function add(Box\T $item) {}
}
=
With `\`, we can also just automatically check the curren= t class as part of namespace resolution when compiling:
class Box<T> {
  public function a= dd(T $item) {}
}

This would a= lso make it easier to user inner classes:

c= lass Outer {
  public class Inner {}
&n= bsp; public function foo(Inner $bar) {}
}
The other syntax options do not allow this; at least, I don= 't think so. I'm very heavily leaning towards `\` as the separator.
<= /div>

=E2=80=94 Rob
<= /div>

I'm failing to understand why you'd think this woul= d be related at all?

If we get generics,

class Box= <T> {
  public function add(T $item) {}
}

would just work, without any use o= r such. There will not be a symbol Box::T or Box\T, just all mentions of= T within the Box class will be taken as "this is the generic placeholde= r" and the compiler takes care.
It's not like that T will = be directly accessible from outside of the class or actually a proper ty= pe, unlike inner classes.

A generic is not = an inner class nor will it look like it. Also, there's no accessing of a= parents generic - you write class Child<T> extends ParentClass<= ;T> - or something along these lines, getting the T available for you= r class.

Bob
Yes, that is the question right? It might not affect anythin= g there, but there would probably be an argument to keep it consistent w= ith inner classes. In PHP, a class is a type; thus an inner class is an = inner type, and generic types are also an inner=0A type that only exist = in the scope of their enclosing class, just like private inner classes.<= br>

If my logic is incorrect, let me know.
<= /div>

=E2=80=94 Rob

The difference is that inner cl= asses are a backed type; there's actually a class/interface/enum/... beh= ind it.

Generic placeholders are placeholde= rs for another type, which is strictly local to the compilation of the c= lass.

Bob

If that were the case, then this would be an error:

function add(T $item) {
  if ($item= instanceof T) {}
}

because T= isn't a backed type. I don't think they are the same thing, but during = runtime, T is most definitely a backed-type; not an empty box. You still= have to refer to T in some way, and I'm of the opinion that self:>T = is not ideal (I think we can probably=0A all agree on that?). Even in in= ner classes, it seems to make more sense to just treat it like you would= any other type in the current namespace.

It's a *placeholder* for a backed type.
= At runtime (or during monomorphization), the T will be replaced by the a= ctual type.

Whatever name T refers to is th= e actual backed type.

Bob

Right, my point is that you have to refer to T = in the first place. If we use `\`, then T as-is is fine, because there i= s a clear resolution to what T you are referring to. If we use :> or = ::, then when you write Box<T>, are you referring to T, as in the = generic T; or T as in the class T in the same namespace. This is clear w= hen we use "T" literally, but quickly becomes not so clear when using so= mething else:

class Item {}
<= br>
class Box<Item> {
  public functi= on add(Item $item) {}
}

This = is exactly why I said this matters! In the case above with the current := > syntax, we should probably use:

class = Box<Item> {
  public function add(self:>Item= $item) {
}

to explicitly def= ine that we want the inner type "Item." To use the first example, you ha= ve to define inner types to allow that, but we are currently defining in= ner types in this RFC. I'd personally rather use the first example when = it comes to generics, which means we need to define that now. In other w= ords, I think you are on team "\" without realizing you are on team "\".=

=E2=80=94 Rob
--39c5f759b1c04975b53a2c870074b7d1--