Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:126844 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 A0ACC1A00BC for ; Wed, 19 Mar 2025 15:04:30 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1742396519; bh=qJp1oyw8xS9dLV8qjfShn6GhtXqd+tBxp7VMuESzq/g=; h=Date:From:To:Cc:In-Reply-To:References:Subject:From; b=Uu80AgfWXZTAPjC2TyrgFMALqxlG7IZm7oQHIHtb6tSxKBO5C8omhJxQxHgSP6MJu aElrqFe15BNlQayGUgDCtPhxLxPaTqrAEeYnUwE/2twcTedcPBYurm+8oj2qNO1G5/ 65VMB3DsLm8a2NqAbyIDpyI2WnbbiFaMk7ITxjNQeFsMDAn7O2s7/kbBABmyqN+YR3 qUnmIWrLCWK1dkWCRmsJvRLBJJk1rAqxDTlFH8FrJbbBsBdGgf6t/O1aQzOwvRZjR9 z4WPyA6z/P+TarwobXDzzGvpjPj7aeSkDp2u5yUJzbJDHHACayQu9xZH7faRfWEcV7 dVukDPAGGi6mQ== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id EE302180032 for ; Wed, 19 Mar 2025 15:01:57 +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 ; Wed, 19 Mar 2025 15:01:57 +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 304A81140122; Wed, 19 Mar 2025 11:04:28 -0400 (EDT) Received: from phl-imap-09 ([10.202.2.99]) by phl-compute-11.internal (MEProxy); Wed, 19 Mar 2025 11:04:28 -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=1742396668; x= 1742483068; bh=eEHHhGf5jnTCoKhNmyn9n/jKiaGBOrf5pXDHgHBAz78=; b=E rAErvM6Dcwbcc8p+Y99DFfngJFpTMxd667hOtQBQSED7IOJwE9jhSb0b0sZC7eXf 5rAUbsYolccoRzhkzzsZ5gSIirz2LgQ7WH9jCLI7qNcgmq++XfHcdG9HBVVM0sgp eETtHycA77JfI6Mj54yMmA8d+6G10LyYUjtCwz/5NPLE3HQ4s3vZ6Y+wdm/8Oh7u RU9OjCqNCqookQWAKaf3Yf3WAJ4rYxwpbsl0xLFkJFQmaCfjmurFusaWt538PCLE TZ92iqbW4SOjE7XXeRT5yzrcR3Jnm5ePN7xZTMveNI+BeQCtIOGcRmsC70LXnfJ7 zpb809ZJbUeLkWsW4GMpA== 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= 1742396668; x=1742483068; bh=eEHHhGf5jnTCoKhNmyn9n/jKiaGBOrf5pXD HgHBAz78=; b=a7HuVhHzTQQrJeWhultba2E/OZZxMC7KUG6M+OcjedP7sAlWnsN YmOhmfYjYL/hubPzv8dD8viCbf1/svBKKAwNgUiMzydc5mOGfc7v3xlo88ASifrw Ea4RwJYxxKrLJEIL1W1aeZ5rPKCjYFtz6Nk+C9exITQzeIWCe2o/EMRMVAtcm3Vq xycTO3lbG6JldR1IzSSsh30fqkw8a7vREc/0y4IatBCzL9dOKcDv97vlj/LoZKym xI84rGlOdXkJ/YpLEZ+W1SKGGg+Kh+09TDUDSatugW3Ppf6MJkXeVXA7GEXZ8nKn tYMSmTrzSUBWJcjjCNl7ezgUXirITk4FlRQ== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefvddrtddtgddugeehieegucetufdoteggodetrf 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 6CC36780068; Wed, 19 Mar 2025 11:04:27 -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: Wed, 19 Mar 2025 16:04:06 +0100 To: "Bob Weinand" Cc: internals@lists.php.net Message-ID: <48dce917-d147-456b-9f03-c7e23411adff@app.fastmail.com> In-Reply-To: References: <3e4ba7ea-a154-452d-abfc-05ef1322fade@app.fastmail.com> <782d76d9-711a-4cee-ae0e-fe0d69973f53@app.fastmail.com> Subject: Re: [PHP-DEV] RFC: short and inner classes Content-Type: multipart/alternative; boundary=cf7c3ad91c50405baeb8b2e09c5cb1c6 From: rob@bottled.codes ("Rob Landers") --cf7c3ad91c50405baeb8b2e09c5cb1c6 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable On Tue, Mar 18, 2025, at 03:37, Bob Weinand wrote: > Hey, >=20 > On 17.3.2025 19:58:39, Rob Landers wrote: >> On Mon, Mar 17, 2025, at 19:05, Bob Weinand wrote: >>>>> . The idea that extending the parent class doesnt no inherit the c= hild classes doesnt make sense to me.=20 >>>>> As then if you extend a parent class and call a function of that c= lass which could rely on the existence of an inner class, I can see a lo= t of headaches caused by this exact scenario. >>>>> As a developer, if I extend a class, I expect the entire dependanc= e of that class to be inherited, otherwise the extending class won't wor= k.=20 >>>>=20 >>>> I'm not sure what you mean. When you inherit a class, you do not ne= cessarily inherit everything from its superclass. You are free to overri= de it however you want. Since we are defining "types" in the sense of PH= P, we cannot merely inherit a "type", otherwise we would cause all kinds= of issues with LSP. This is specifically why inheritance works the way = it does in this RFC and why `static::` is forbidden. >>> I don't understand the problem here. >>>=20 >>> for each nested class in parent class: >>> class_alias(substitute parent class with child class in class na= me, class name) >>> Very simple. There's no magic needed, it can be simply class aliases= . This will also make static, self and parent trivially work. >>>=20 >>=20 >> PHP doesn't go out of its way to prevent the developer from violating= LSP -- but where it can, it does. If a type were inherited, then the su= bclasses wouldn't be able to guarantee that an inner/nested class implem= ented the parent inner/nested class. Or, if it did, it would require tha= t all subclasses using a class of the same name MUST inherit from the pa= rent class as well. >>=20 >> This is non-trivial to implement as the parent class may or may not h= ave been compiled yet when we are compiling the subclass. So, we have no= idea what the parent class actually looks like until runtime. Further, = it is much simpler to reason about each class as a distinct type vs. may= be inheriting a type from a supertype. >>=20 >> Thus, if you want to inherit from the super-class's inner classes, yo= u can, but this RFC won't force you to do so. In my mind, this is the bi= ggest argument for a `\`, because the enclosing class acts more like a n= amespace than a type, from the perspective of the inner class. >>=20 >> If we were to embrace `\`, then it could be argued that a namespace i= s technically a class in itself, (but a partial class, to borrow from C#= terminology) and every class in a namespace is essentially just a publi= c class in that super-class/namespace. >>=20 >> Nobody has argued that perspective, but I believe it may be interesti= ng (and would lay a foundation for namespace private/public class behavi= or/visibility). That being said, it truly does cause issues with autoloa= ding -- at least, PSR-4 autoloading -- and I'm not sure whether we shoul= d solve that problem here; however, it is something to be cognizant of, = for sure. There are other types of autoloading supported by tools, such = as composer, that do not have any issues with using `\` as a separator. > 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 = ignore it. >=20 > (Effectively implementing LSP would mean that there's an implicit inte= rface matching all public method signatures of the parent class, for chi= ld classes - which is doable, but possibly too much for the initial RFC.) >=20 >=20 > I would however ask, should we not implement LSP compatible inner clas= ses, to enforce that no child class may name a class the same than any n= on-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 futur= e. >=20 I'm not sure I understand what you are asking. But I think you are sayin= g the following should be illegal? class ParentOuter { class ParentInner {} } class ChildOuter extends ParentOuter { class ParentInner {} // not allowed } >=20 > However nice grand unified naming schemes may seem, I don't think it's= a good idea to pursue. Clarity and explicitness shall reign supreme her= e. > I also don't think that the proposed visibilities are applicable to na= mespaced classes. In particular and in practice shared internal classes = are not necessarily directly organized in a way it makes sense to organi= ze inner classes. Also visibilities like protected propagate along the i= nheritance chain, something which is not given with (outer) namespaced c= lasses. > The less we mix these slightly different concepts, the better. >=20 >=20 > "It's similar, except in these and those cases" is the death of all co= nsistent experiences. Thus, let's not even attempt to pretend it is. >=20 This is true. >=20 > And not pretending starts with using a different symbol than a backsla= sh. >=20 I have been thinking about this for a couple of days now... When thinkin= g through the ramifications of my decision to use :> over ::, this will = also affect generics, most likely -- whenever that happens. This is beca= use if this RFC passes, generics will want to be consistent with whateve= r exists currently. If we were to use :>, then generics would probably look something like t= his 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 --cf7c3ad91c50405baeb8b2e09c5cb1c6 Content-Type: text/html; charset=utf-8 Content-Transfer-Encoding: quoted-printable
On Tue, Mar = 18, 2025, at 03:37, Bob Weinand wrote:

Hey,

= On 17.3.2025 19:58:39, Rob Landers=0A wrote:
On Mon, Mar 17, 2025, at 19:05, Bob Weinand wrote:
=
. = The idea that extending the parent class doesnt=0A no i= nherit the child classes doesnt make sense to me. 
As then if you extend a parent class and call a=0A f= unction of that class which could rely on the=0A existe= nce of an inner class, I can see a lot of=0A headaches = caused by this exact scenario.
As a developer, if I extend= a class, I expect the=0A entire dependance of that cla= ss to be inherited,=0A otherwise the extending class wo= n't work. 

I'= m not sure what you mean. When you inherit a class, you=0A do= not necessarily inherit everything from its superclass.=0A Y= ou are free to override it however you want. Since we are=0A = defining "types" in the sense of PHP, we cannot merely=0A inh= erit a "type", otherwise we would cause all kinds of=0A issue= s with LSP. This is specifically why inheritance works=0A the= way it does in this RFC and why `static::` is forbidden.

I don't understand the problem here.

for each nes= ted class in parent class:
    class_alias(= substitute parent class with child class=0A in class name, clas= s name)

Very simple. There's no magic needed, it can be simp= ly class=0A aliases. This will also make static, self and paren= t trivially=0A work.


PH= P doesn't go out of its way to prevent the developer from=0A viol= ating LSP -- but where it can, it does. If a type were=0A inherit= ed, then the subclasses wouldn't be able to guarantee=0A that an = inner/nested class implemented the parent inner/nested=0A class. = Or, if it did, it would require that all subclasses using=0A a cl= ass of the same name MUST inherit from the parent class as=0A wel= l.

This is non-trivial to implement as the = parent class may or=0A may not have been compiled yet when we are= compiling the=0A subclass. So, we have no idea what the parent c= lass actually=0A looks like until runtime. Further, it is much si= mpler to reason=0A about each class as a distinct type vs. maybe = inheriting a type=0A from a supertype.

Thus, if you want to inherit from the super-class's inner=0A c= lasses, you can, but this RFC won't force you to do so. In my=0A = mind, this is the biggest argument for a `\`, because the=0A encl= osing class acts more like a namespace than a type, from the=0A p= erspective of the inner class.

If we were t= o embrace `\`, then it could be argued that a=0A namespace is tec= hnically a class in itself, (but a partial=0A class, to borrow fr= om C# terminology) and every class in a=0A namespace is essential= ly just a public class in that=0A super-class/namespace.

Nobody has argued that perspective, but I believe i= t may be=0A interesting (and would lay a foundation for namespace= =0A private/public class behavior/visibility). That being said, it= =0A truly does cause issues with autoloading -- at least, PSR-4=0A= autoloading -- and I'm not sure whether we should solve that=0A = problem here; however, it is something to be cognizant of, for=0A= sure. There are other types of autoloading supported by tools,=0A= such as composer, that do not have any issues with using `\` as=0A= a separator.

Okay, I see the point with= LSP. I'm not sure whether we need to=0A preserve LSP for that spec= ific scenario, but neither can I say=0A that we should ignore it.

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

I would however ask,= should we not implement LSP compatible inner=0A classes, to enforc= e that no child class may name a class the same=0A than any non-pri= vate inner class declared by any of its parents,=0A until we resolv= e this question (in possibly a future version of=0A PHP).
=
I do not think we should bar ourselves from allowing this in the=0A= future.


I'm not s= ure I understand what you are asking. But I think you are saying the fol= lowing should be illegal?

class ParentOuter= {
  class ParentInner {}
}

class ChildOuter extends ParentOuter {
&= nbsp; class ParentInner {} // not allowed
}
=

How= ever nice grand unified naming schemes may seem, I don't think=0A i= t's a good idea to pursue. Clarity and explicitness shall reign=0A = supreme here.
I also don't think that the proposed visibi= lities are applicable=0A to namespaced classes. In particular and i= n practice shared=0A internal classes are not necessarily directly = organized in a way=0A it makes sense to organize inner classes. Als= o visibilities like=0A protected propagate along the inheritance ch= ain, something which=0A is not given with (outer) namespaced classe= s.
The less we mix these slightly different concepts, the= better.

"It's similar, except in these and = those cases" is the death of=0A all consistent experiences. Thus, l= et's not even attempt to=0A pretend it is.


This is true.

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


I have been thinking about this for a = couple of days now... When thinking through the ramifications of my deci= sion to use :> over ::, this will also affect generics, most likely -= - whenever that happens. This is because if this RFC passes, generics wi= ll want to be consistent with whatever exists currently.
<= br>
If we were to use :>, then generics would probably look= something like this to be consistent:

clas= s Box<T> {
  public function add(self:>T $it= em) {}
}

The same thing would= also probably apply to ::

class Box<T&g= t; {
  public function add(self::T $item) {}
}

With `\`, it nearly follows exactly= what you would expect-ish:

use \Box\T as T= ;

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

// or with= out use
  public function add(Box\T $item) {}
}

With `\`, we can also just automat= ically check the current class as part of namespace resolution when comp= iling:

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

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

class Outer {
  public class In= ner {}
  public function foo(Inner $bar) {}
=
}

The other syntax options do not allow th= is; at least, I don't think so. I'm very heavily leaning towards `\` as = the separator.

=E2=80=94= Rob
--cf7c3ad91c50405baeb8b2e09c5cb1c6--