Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:126889 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 92AFF1A00BC for ; Fri, 21 Mar 2025 11:15:50 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1742555599; bh=Q2QsOe95ZxoGKh8RApQnDVMfF3VW/Sjz/7DVF4Biu0E=; h=References:In-Reply-To:From:Date:Subject:Cc:From; b=nr6L5JUE2o4rZSF9FNDWMprR1pU4YS9Ivj9A4dkurxY9gc4it2hxvrvLwxiebFCC7 XD7/PGaWTEP46CKPBCO7VRvfcEy+zUKXOCDku+VXREQTAjI1odlasPHi1mT0wvRK4w uhgkP5nP+6rZEeqe0nq8pZuVS9n3xsJOw7ImD77wsXfCYSZjqcupsiv1yLNFHHx/Eo XKqxMazBti62DeEqlQPpoH1mh/EL8nWwBQmYGcB3ErpKXZuswfXiSslkF4wki6h/tB xPoGEuk5jUbup5kG4QOsEzeFedtvz7RMI2GpzaaunNgJgbXKiIVN69o8KHAmq6B5EI IC8WJZRGW+U7g== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 7C68C1804D7 for ; Fri, 21 Mar 2025 11:13:18 +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.7 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_PASS,FREEMAIL_FROM, HTML_MESSAGE,MALFORMED_FREEMAIL,MISSING_HEADERS,RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_PASS autolearn=no autolearn_force=no version=4.0.0 X-Spam-Virus: No X-Envelope-From: Received: from mail-wm1-f52.google.com (mail-wm1-f52.google.com [209.85.128.52]) (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, 21 Mar 2025 11:13:18 +0000 (UTC) Received: by mail-wm1-f52.google.com with SMTP id 5b1f17b1804b1-43cec5cd73bso11853415e9.3 for ; Fri, 21 Mar 2025 04:15:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1742555747; x=1743160547; darn=lists.php.net; h=cc:subject:message-id:date:from:in-reply-to:references:mime-version :from:to:cc:subject:date:message-id:reply-to; bh=0Ii1AgtJYAyLEp4jzp0mmTO1wXnDDD8gWRFNU/PCvSU=; b=fPgWoD69zxqjWyV9qqcdABXMR7g6C43cLqAg+3T9Ymkv9uQ59VvdQouvCqhG8yB7NI euO7Umlm6IhaWDJOCH7/DHG56UjSNwGm2T5YYmO7xCeAsrfyALXIV6scycWJf28f44kC bR+4YDp9N9V4uCpXxwhitGisXZtw5Nbtdl47CRtEPHYUGwsZLYpW7qH9ymUjb98yokTD qGoDIqX3H07IA3oTq1FEmOxebnKJbeVGoKIif2dSyS3zngZb6OGUO9993SbeE7tetO3S /hI82uuW3fFENHme+cyX0uQ2B/RmXvreZxx9a87aH+S9gPlXrG2ansLwVL7I2b0JRTDH 7FzA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1742555747; x=1743160547; h=cc:subject:message-id:date:from:in-reply-to:references:mime-version :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=0Ii1AgtJYAyLEp4jzp0mmTO1wXnDDD8gWRFNU/PCvSU=; b=sqzSXcgRLc4Q//K0TEd6v0tp26JEfYrc5O/Y8AaAI1HqvOa7ctWFoHxQT08kxZE7X9 /UVbF5shxwZoLqHegGwd/hVJ6Imp4m9oxFHPEKvPWhKi3cFbBYQ75qWWqEtqPg3tAtar E2+qru7gzqKMzWATs3PxpuIAdYJ+CmyKTizqSqhzZqfZuX74e0x/fkCCSL+Tm1MTZ7T1 oUF860MCrS/8y3BL2RdPe3F44ed2/nx4wxOa3TQKuzZKHN7vMLFXrQavjBbLwN3ryq98 X722JvN9jhiGXQCuoEYQTxTZ1kt4/8vABZ/UbAgl0pDnDh2nvPyqylHGUHe99VJloOHt O08g== X-Gm-Message-State: AOJu0Yxx1/Z/d9fXPUonpkHhfeHqNtZhmF5k+GIsLCXl0nVe66gGkMqM 9k4rlkWlYQ2HxxjFAjkF4gB9BkAKnJ+zsVqwvf0lgKmAk1DujtmpmhVlQ+yDscCSJU9obkw7cXB P47n5MF0HN6q0xF7pH9vPguFMbFfU+iPA X-Gm-Gg: ASbGncvH953qxXjBv1iAev+4Ydotc95pX8MraOrq7dPUAyU51tOVE99HdFRxC2STOKO /oL37OHfzWyZZlmQaX/SCls5AUL42+H2Th5n+ziNgy+w4kEfj2dE6yVDrC7vGVpNEOPNR4ej/lE DPpWHsUymdchGr6X8Iv2IwM8XZbtTzvFwVFG/M X-Google-Smtp-Source: AGHT+IE4l93tEbiliFVEOoUDef9YMnIE7Rwqcx4ijrOAuwpUg0kJGYLMdFIO1FQrIRqUGoJnPt9rl+VNEJwBMOH8+Fk= X-Received: by 2002:a05:600c:3ba7:b0:43d:ac5:11ed with SMTP id 5b1f17b1804b1-43d568c3705mr2249635e9.24.1742555746743; Fri, 21 Mar 2025 04:15:46 -0700 (PDT) Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net x-ms-reactions: disallow MIME-Version: 1.0 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> <5b1e6d70-a1c9-455c-93d3-6b22cf1fef11@app.fastmail.com> In-Reply-To: <5b1e6d70-a1c9-455c-93d3-6b22cf1fef11@app.fastmail.com> Date: Fri, 21 Mar 2025 13:15:34 +0200 X-Gm-Features: AQ5f1Jpm8qlHs4yMKKH0R-Ow3LhtWr0bRfxdPdBnZs9Eadiyr5hZIZm71wRcdNQ Message-ID: Subject: Re: [PHP-DEV] RFC: short and inner classes Cc: PHP internals Content-Type: multipart/alternative; boundary="000000000000493fad0630d86061" From: raveren@gmail.com (=?UTF-8?Q?Rokas_=C5=A0leinius?=) --000000000000493fad0630d86061 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Thu, Mar 20, 2025, 18:58 Rob Landers wrote: > > > On Thu, Mar 20, 2025, at 16:41, Bob Weinand wrote: > > > Am 20.03.2025 um 16:28 schrieb Rob Landers : > > =EF=BB=BF > > > On Thu, Mar 20, 2025, at 16:12, Bob Weinand wrote: > > > Am 20.03.2025 um 15:51 schrieb Rob Landers : > > =EF=BB=BF > > > On Wed, Mar 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 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 should igno= re > it. > > (Effectively implementing LSP would mean that there's an implicit > interface matching all public method signatures of the parent class, for > child classes - which is doable, but possibly too much for the initial RF= C.) > I would however ask, should we not implement LSP compatible 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 of PHP). > I do not think we should bar ourselves from allowing this in the future. > > > I'm not sure I understand what you are asking. But I think you are saying > the following should be illegal? > > class ParentOuter { > class ParentInner {} > } > > class ChildOuter extends ParentOuter { > 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 als= o > affect generics, most likely -- whenever that happens. This is because if > this RFC passes, generics will want to be consistent with whatever exists > currently. > > If we were to use :>, then generics would probably look something like > this to be consistent: > > class Box { > public function add(self:>T $item) {} > } > > The same thing would also probably apply to :: > > class Box { > public function add(self::T $item) {} > } > > With `\`, it nearly follows exactly what you would expect-ish: > > use \Box\T as T; > > class Box { > public function add(T $item) {} > > // or without use > public function add(Box\T $item) {} > } > > With `\`, we can also just automatically check the current class as part > of namespace resolution when compiling: > > class Box { > public function add(T $item) {} > } > > This would also make it easier to user inner classes: > > class Outer { > public class Inner {} > 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. > > =E2=80=94 Rob > > I'm failing to understand why you'd think this would be related at all? > > If we get generics, > class Box { > public function add(T $item) {} > } > > would just work, without any use or such. There will not be a symbol > Box::T or Box\T, just all mentions of T within the Box class will be take= n > as "this is the generic placeholder" and the compiler takes care. > It's not like that T will be directly accessible from outside of the clas= s > or actually a proper type, unlike inner classes. > > A generic is not an inner class nor will it look like it. Also, there's n= o > accessing of a parents generic - you write class Child extends > ParentClass - or something along these lines, getting the T available > for your class. > > Bob > > > Yes, that is the question right? It might not affect anything there, but > there would probably be an argument to keep it consistent with inner > classes. In PHP, a class is a type; thus an inner class is an inner type, > and generic types are also an inner type that only exist in the scope of > their enclosing class, just like private inner classes. > > If my logic is incorrect, let me know. > > =E2=80=94 Rob > > > The difference is that inner classes are a backed type; there's actually = a > class/interface/enum/... behind it. > > Generic placeholders are placeholders for another type, which is strictly > local to the compilation of the class. > > 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 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. > > > It's a *placeholder* for a backed type. > At runtime (or during monomorphization), the T will be replaced by the > actual type. > > Whatever name T refers to is the 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 is a clear resolution to wha= t > T you are referring to. If we use :> or ::, then when you write Box, a= re > you referring to T, as in the generic T; or T as in the class T in the sa= me > namespace. This is clear when we use "T" literally, but quickly becomes n= ot > 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 > current :> 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 first > example, you have to define inner types to allow that, but we are current= ly > defining inner 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 words, I think you are on team "\" without realizing you are on > team "\". > > =E2=80=94 Rob > Hello all, amazing effort as always. My 2=C2=A2: RL usecase I immediately would adopt this for - is building IDE-supported complex DTOs. This means autocompletion, refactor rename, inspections for undefined keys, etc for the price of using no language =E2=80=9Dhacks=E2=80= =9D. A real life example - json response from UPS shipping API - it has 200++ keys in up to 10+ levels! The structure keeps changing too, albeit in glacial speeds, but having it in a structured definition allows one to not loose ones head when providing continuous support. However: there's a *bunch* of multilevel =E2=80=9Dleaf nodes=E2=80=9D which= are reused dozends of times, for example MonetaryAmount - it has the numeric value, but also a Currency as a property. If extending a class does not inherit the public/protected nested classes, we are forced to define the structure of MonetaryAmount in the =E2=80=9Dreg= ular=E2=80=9D fashion as separate classes. Not to mention this non-inheritance is counter-inuitive IMHO. Also, IMHO =E2=80=9Dnested classes=E2=80=9D is a better name. Good luck! > --000000000000493fad0630d86061 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
On Thu, Mar 20, 2025, 18:58 Rob Landers = <rob@bottled.codes> wrote:


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

=
Am 20.03.2025 um 16:28 schrieb Rob Landers &= lt;rob@bottled.codes>:
=EF=BB=BF


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

Am 20.03.2025 um 15:51 s= chrieb Rob Landers <rob@bottled.codes>:
<= blockquote type=3D"cite">
=EF=BB=BF

=

On Wed, Mar 19, 2025, at 21:09, Bob Weinand wrote= :
<= p>

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 preser= ve LSP for that specific scenario, but neither can I say that we should ign= ore it.

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

I would however ask, should we not implement LSP c= ompatible inner classes, to enforce that no child class may name a class th= e same than any non-private inner class declared by any of its parents, unt= il we resolve this question (in possibly a future version of PHP).
I do not think we should bar ourselves from allowin= g this in the future.

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

class ParentOuter {
=C2=A0 class ParentInner {}
}

=
class ChildOuter extends ParentOuter {
=C2=A0 clas= s ParentInner {} // not allowed
}

Pr= ecisely.

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

<= div>I have been thinking about this for a couple of days now... When thinki= ng through the ramifications of my decision to use :> over ::, this will= also affect generics, most likely -- whenever that happens. This is becaus= e if this RFC passes, generics will want to be consistent with whatever exists currently.

If we were to use :>, then generics would probably look somethi= ng like this to be consistent:

class Box<T&= gt; {
=C2=A0 public function add(self:>T $item) {}
}

The same thing would also probably ap= ply to ::

class Box<T> {
= =C2=A0 public function add(self::T $item) {}
}
=
With `\`, it nearly follows exactly what you would expect-is= h:

use \Box\T as T;

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

// or without use
=C2=A0 publi= c function add(Box\T $item) {}
}

With `\`, we can also just automatically check the current class as part o= f namespace resolution when compiling:

class B= ox<T> {
=C2=A0 public function add(T $item) {}
}

This would also make it easier to user= inner classes:

class Outer {
= =C2=A0 public class Inner {}
=C2=A0 public function foo(Inner= $bar) {}
}

The other syntax opt= ions do not allow this; at least, I don't think so. I'm very heavil= y leaning towards `\` as the separator.

=E2=80=94 Rob

I'm failing to understand why you'd think this would be rel= ated at all?

If we get generics,

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

would just work, without any use or such. There wil= l not be a symbol Box::T or Box\T, just all mentions of T within the Box cl= ass will be taken as "this is the generic placeholder" and the co= mpiler takes care.
It's not like that T will be directly = accessible from outside of the class or actually a proper type, unlike inne= r 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 somethin= g along these lines, getting the T available for your class.
=
Bob

Yes, that is t= he question right? It might not affect anything there, but there would prob= ably be an argument to keep it consistent with inner classes. In PHP, a cla= ss is a type; thus an inner class is an inner type, and generic types are a= lso an inner type that only exist in the scope of their enclosing class, just like priv= ate inner classes.

If my logic is incorrect, l= et me know.

=E2=80=94 Rob

= The difference is that inner classes are a backed type; there's actuall= y a class/interface/enum/... behind it.

Generi= c placeholders are placeholders for another type, which is strictly local t= o the compilation of the class.

Bob
<= /blockquote>

If that were the case, then this would be a= n error:

function add(T $item) {
=C2=A0 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 empt= y 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 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.
<= /div>

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

Whatever n= ame T refers to is the 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, bec= ause there is 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 i= n the generic T; or T as in the class T in the same namespace. This is clea= r when we use "T" literally, but quickly becomes not so clear whe= n using something else:

class Item {}

class Box<Item> {
=C2=A0 public fu= nction add(Item $item) {}
}

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

class Box&l= t;Item> {
=C2=A0 public function add(self:>Item $item) = {
}

to explicitly define that we= want the inner type "Item." To use the first example, you have t= o define inner types to allow that, but we are currently defining inner typ= es in this RFC. I'd personally rather use the first example when it com= es to generics, which means we need to define that now. In other words, I t= hink you are on team "\" without realizing you are on team "= \".

= =E2=80=94 Rob

Hello all, amazing effort as= always.

My 2=C2=A2:

RL usecase I immediately would adopt this for - is buildin= g IDE-supported complex DTOs. This means autocompletion, refactor rename, i= nspections for undefined keys, etc for the price of using no language =E2= =80=9Dhacks=E2=80=9D.

A real life example - json response from UPS shipping = API - it has 200++ keys in up to 10+ levels! The structure keeps changing t= oo, albeit in glacial speeds, but having it in a structured definition allo= ws one to not loose ones head when providing continuous support.

However: the= re's a *bunch* of multilevel =E2=80=9Dleaf nodes=E2=80=9D which are reu= sed dozends of times, for example=C2=A0MonetaryAmount - it has the numeric = value, but also a Currency as a property.

If extending a class does not inher= it the public/protected nested classes, we are forced to define the structu= re of MonetaryAmount in the =E2=80=9Dregular=E2=80=9D fashion as separate c= lasses.

Not to mention this non-inheritance is counter-inuitive IMHO.

Also, IMH= O =E2=80=9Dnested classes=E2=80=9D is a better name.

Good luck!
--000000000000493fad0630d86061--