Re: RFC: short and inner classes

From: Date: Wed, 19 Mar 2025 15:04:06 +0000
Subject: Re: RFC: short and inner classes
References: 1 2 3 4 5 6  Groups: php.internals 
Request: Send a blank email to internals+get-126844@lists.php.net to get a copy of this message
On Tue, Mar 18, 2025, at 03:37, Bob Weinand wrote: > Hey, > > 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 child classes >>>>> doesnt make sense to me. >>>>> As then if you extend a parent class and call a function of that class which >>>>> could rely on the existence of an inner class, I can see a lot of headaches caused by this exact >>>>> scenario. >>>>> As a developer, if I extend a class, I expect the entire dependance of that >>>>> class to be inherited, otherwise the extending class won't work. >>>> >>>> I'm not sure what you mean. When you inherit a class, you do not necessarily >>>> inherit everything from its superclass. You are free to override it however you want. Since we are >>>> defining "types" in the sense of PHP, 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. >>> >>> for each nested class in parent class: >>> class_alias(substitute parent class with child class in class name, 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. >>> >> >> 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 subclasses wouldn't be able to guarantee >> that an inner/nested class implemented the parent inner/nested class. Or, if it did, it would >> require that all subclasses using a class of the same name MUST inherit from the parent class as >> well. >> >> This is non-trivial to implement as the parent class may or may not have 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. maybe >> inheriting a type from a supertype. >> >> Thus, if you want to inherit from the super-class's inner classes, you can, but this >> RFC won't force you to do so. In my mind, this is the biggest argument for a >> \, because the enclosing class acts more like a namespace than a >> type, from the perspective of the inner class. >> >> If we were to embrace \, then it could be argued that a >> namespace is technically a class in itself, (but a partial class, to borrow from C# terminology) and >> every class in a namespace is essentially just a public class in that super-class/namespace. >> >> Nobody has argued that perspective, but I believe it may be interesting (and would lay a >> foundation for namespace private/public class behavior/visibility). That being said, it truly does >> cause issues with autoloading -- at least, PSR-4 autoloading -- and I'm not sure whether we >> should 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 preserve LSP for that > specific scenario, but neither can I say that we should ignore 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 RFC.) > > > 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 } > > 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 here. > I also don't think that the proposed visibilities are applicable to namespaced classes. In > particular and in practice shared internal classes are not necessarily directly organized in a way > it makes sense to organize inner classes. Also visibilities like protected propagate along the > inheritance chain, something which is not given with (outer) namespaced classes. > The less we mix these slightly different concepts, the better. > > > "It's similar, except in these and those cases" is the death of all consistent > experiences. Thus, let's not even attempt to pretend it is. > This is true. > > 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. 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<T> { public function add(self:>T $item) {} } The same thing would also probably apply to :: class Box<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 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<T> { 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. — Rob

« previous php.internals (#126844) next »