On Mon, Mar 17, 2025, at 19:05, Bob Weinand wrote:
> Hey Rob,
> 
> On 17.3.2025 17:53:26, Rob Landers wrote:
>> On Mon, Mar 17, 2025, at 16:30, fennic log wrote:
>>> 2. As with any syntax change and new operator there needs to be very 
>>> careful consideration, do we need a new operation, or could `::` if the 
>>> parent is static or `->` if the class is initialized?
>> 
>> There's quite a long thread already about this very topic. That being said, 
>> the inner class has no bearing on whether the outer class is instantiated or 
>> not. Originally, I used `::` as the separator, but it seems there are some 
>> good arguments for `\`, so we will see.
> I have not grasped any single argument in favour of \, except "other 
> languages are doing it too", "existing tooling splitting on backslash would 
> continue to work" and "we could use the existing use statement as is".
> 
> 
> The problems are numerous though:
> 1. Unlike other languages (e.g. C# and java), namespaces and classes may 
> share a name in PHP. E.g. class "Y" in a namespace "X" and class "X" may not 
> exist both. In PHP that's allowed. Inner classes compete with namespaced 
> classes for their fully qualified name.
> 2. Autoloading will have to become aware of inner classes.
> 3. Autoloading will have to do a non-cacheable check for existence on the 
> inner class, before iteratively testing whether any parent has a respective 
> .php file. Currently autoloading takes a class name, transforms it to a 
> single canonical path, and includes it. Always succeeding.
> 4. Humans, navigating to a path, will not be able to navigate to a file 
> directly but have to search for it.
> 5. Tooling splitting on backslash might assume the 1:1 mapping to the 
> filesystem and break. It's really not a catch all. Some things may be broken 
> and some not, but all need to be probably revisited anyway.
> 6. It makes accessing via parent, self or static weird. These keywords have 
> always been followed by a double colon. (Even if this particular RFC does not 
> end up adding them) And it will conflict with a namespace named "parent" for 
> example.
> 7. At least right now, every backslash identified symbol is trivially 
> universally public. With \ as an inner class separator, this would no longer 
> be the case. Maybe that will eventually change, but today this can be relied 
> upon.
> 
> Also, just because other languages are doing a mistake, it does not mean we 
> have to repeat it. They are generally doing it because their identifier 
> separator is universal and it's consistent. It does not mean that it's 
> without its own problems.
> 
> 
> Using the double colon is a very minor BC break (accessing a class by a class 
> constant value?! That's also quite inconsistent that it works at all, as you 
> can't do that with normal constants, only class constants.).
> Using another sigil would also be possible (like :>). But for the backslash I 
> only see drawbacks.
> 
> Also, nothing precludes us from allowing "use Foo\Bar::Inner;".
> 
> 
> 
>>> 3. 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.

> On 15.3.2025 00:37:08, Rob Landers wrote:
> 
> 
> 
>> Classes don't actually know their inner classes -- they aren't like 
>> properties. In essence, an inner class is just a regular class with a funny 
>> name and access to scopes it wouldn't normally have access to. We could 
>> probably add `getOuterClass(): string` if that is useful. It is possible to 
>> keep track of a class's inner classes, but then that introduces a paradox 
>> chicken/egg type problem during construction, which may or may not be a 
>> problem.
>> 
> 
> 
> I don't see the chicken-and-egg problem here. You can simply collect all the 
> inner class names at compilation. You don't even need to actually store the 
> zend_class_entry - just collect the names and fetch from the class table at 
> runtime (and ignore missing ones, e.g. if there was an error during linking).
> 

🙃sometimes the obvious solutions are the best solutions.

— Rob

Reply via email to