Hi Rob On Thu, Mar 13, 2025 at 1:57 PM Rob Landers <rob@bottled.codes> wrote: > > > the proposal is > > currently quite complex. > > Most of this is just describing how classes work already and going in-depth > on where there may be confusion -- there are no significant changes to how > classes actually work. The actual changes to the engine are basically just > visibility rules, some syntax changes (to allow nesting `class` inside > another class), and handling the new operator. The hard part is explaining > how classes work, because they don't really have a defined behavior. In other > words, I cannot just say "the way this works doesn't change anything."
Well, you cut out the examples I gave: > It has a custom operator, it deals with shadowing, LSP, runtime resolution > and more, in addition to visibility which is the actual goal. Those are > unrelated to existing behavior, they are introduced in the proposal. * The custom operator and runtime resolution is not something that technically needs to be there. The name of class Foo { class Bar {} } could simply be Foo\Bar. I've mentioned before that this does not work with PSR-4, but there's no reason it can't work with autoloading at all. An extended autoloading spec could recursively search Foo/Bar/Baz.php, then Foo/Bar.php, and so forth. Given this happens only when loading the class, and nesting would usually be limited in quantity and amount, that seems like a reasonable solution, and Composers optimized autoloader could avoid it entirely. This would also solve the same issue for sealed classes, assuming they're named in a similar fashion. * By shadowing I referred to static:>MyClass. This makes it more modular, but it's also another layer of complexity and indirection. You haven't really provided a reasoning and examples of how this could be used. It's also not clear if this can be prevented. The inner class can be marked as final, but that wouldn't stop you from shadowing the inner class without extending it. Similarly, static:>MyClass would have no type guarantees, given that it can be shadowed by any classes, not just classes that are compatible. class Outer { protected class Inner { public static function innerTest() {} } public static function outerTest() { static:>Inner::innerTest(); } } class OuterV2 extends Outer { protected class Inner {} // This breaks outerTest() } * LSP issues have been mentioned before. You can use self:>Inner in method signatures even if the inner classes are private. The method could be called from sub-classes, but they couldn't ever override it, since there's no way to satisfy the parent signature. This makes it implicitly final. Not technically a problem, just odd. As mentioned, maybe there are additional use-cases this complexity can cover, but the RFC doesn't give many examples. If the primary reason for this complexity is just visibility, then I don't think this is the simplest and best way in which that goal could be achieved. > > They might > > still be ok if they are extremely simple > > And now you can understand why they WERE just simple classes (short classes). > So, you can see why I originally bundled them together because of this EXACT > argument. :sigh: The arguments above are not limited to complex classes. Simple classes would apply to. * The :> operator is still something new that I don't believe needs to be there. * Shadowing simple classes can still cause incompatibilities between constructors. * The LSP issue applies. * As soon as we try to add support for complex classes, we'll run into the same questions again. Thinking ahead is always worth it, to prevent us from running into issues later. Doesn't mean everything needs to land at the same time ofc. Ilija