Re: [RFC] Static class

From: Date: Thu, 27 Jun 2024 06:11:51 +0000
Subject: Re: [RFC] Static class
References: 1 2 3 4 5 6 7 8  Groups: php.internals 
Request: Send a blank email to [email protected] to get a copy of this message

> On Jun 27, 2024, at 12:09 AM, Stephen Reay <[email protected]> wrote:
> 
> Hi Mike,
> 
> To answer your question: I believe abstract static should be allowed, because the
> "objection" mis-characterises a particular aspect of them as an unintended consequence,
> when there's evidence to show that's not that case.
> 
> Claude essentially dismisses the use of abstract static methods:
> 
>>> only consequences of their intended meaning on non-static class
> 
> In v5.2 a strict standards notice was added regarding the use of abstract static methods in
> classes. No notice was ever shown when they're used in interfaces.  In v7 this notice was
> removed (via https://wiki.php.net/rfc/reclassify_e_strict#abstract_static_methods
> <https://wiki.php.net/rfc/reclassify_e_strict#abstract_static_methods>)
> because, as Nikita noted at the time:

Thank you for elaborating. 

We are on the same page here as I too think abstract static should be allowed when
declaring a class

>> We currently allow the use of abstract static functions in interfaces, as such it is
>> inconsistent to not allow them as abstract methods. By using late static binding a method in the
>> abstract class can reasonably depend on the existence of a static method in a superclass. 
> 
> 
> That to me says this is an intended feature, and not an unintended consequence.

Before I address this and your other comments, please understand that I do not see this as a huge
issue either way, but I do want my argument to be understood. If my argument on this does not win
the day, I will not lament it in any way.

As an aside, I had never seen interfaces used that way and found it surprising. Obviously I missed
when Nikita made that claim.  

As for "an intended feature, and not an unintended consequence," when I was in university
they drilled the idea of a sunken cost into me to the point I am a true believer. IOW, make the best
decision moving forward vs. doubling down on bad decisions. 

Note that I am not saying Nikita's was a bad decision (or a good one) just that the existence
of a prior decision should not color making the best decision moving forward.

I am curious, do you know of real-world userland code that is actually configured as your example
that would be negatively affected by disallowing static methods calls?

> On Jun 26, 2024, at 4:26 AM, Stephen Reay <[email protected] <mailto:[email protected]>> wrote:

> 

> This is an example of code that works today (and all the way back to 5.0): https://3v4l.org/4EKo2 <https://3v4l.org/4EKo2>The class hierarchy embody the type of
> classes this RFC is about: only static members, no instantiation. 

> 

> The *implemented methods* can be called statically, regardless of whether the class
> they're implemented in is abstract or not. The *abstract methods* cannot be called directly.

Understood, but I do not see how interfaces or instantiation or abstract method are relevant to the
discussion. They all seem orthogonal to me.

> So these classes would be a candidate for the static class keyword (or Attribute)
> - except they can't, if calls to implemented methods on abstract classes are disallowed.
> Because the Base::a() method has been publicly callable, for potentially as long as <checks
> notes>  20 years next month.

While it may be true that it has been that way, disallowing static methods from being
called using abstract static classes would not be a BC break because it was previously
impossible to declare a class as static let alone abstract static.

Further, there are often new features with constraints that result in developer not being "to
do what they have been able to do for 20 years" because, looking forward, those constraints
make more sense than not having those constraints. 

Take a look at readonly properties. They must be typed, but I could have used the same
argument against that saying "We've always been able to have untyped properties so
readonly should not have to be typed."[1] I'd say requiring them to be typed was a win,
though, regardless of past property capabilities.

I'm not claiming necessarily that disallowing calling static methods on a
abstract static class is a best practice, but I am saying that "we've been
able to do it with similar syntax for a long time" is not a particularly compelling argument if
disallowing is a better approach.

As another aside, assuming everyone agrees on what a best practice is for a given case, I doubt
anyone would object to a constraint that forced developers to follow that best practice vs. allowing
them to write less ideal code.

> My point here is that if someone wants to prohibit calling public static methods on abstract
> classes *with* the static keyword, that's going be inconsistent with how it's worked for
> the last 20 years (i.e. on classes that were 'static' in intent but not syntactically),

Back to sunken cost, does it make more sense to only give developers who want to disallow using
static methods for their abstract static classes access to @internal
docblock — which I argued against elsewhere in this thread — and let Hyrum's Law
take over, OR do we enable them to disallow calling those static methods from the
abstract class itself?

More importantly, IF we do not immediately disallow calling static methods on
abstract static classes then we will never be able to disallow in the future, because
of BC. But on the flip side we could later open them up for calling if we found the limitation to be
problematic.

>  or if it applies the change everywhere it's going to be a BC break.

And to be clear, I am against BC breaks in almost all cases. So bringing that up between us is moot.

All that said, if you tell me "I don't care about closing the door on being able to
disallow developers from calling static methods on abstract static methods because
prior to abstract static classes static methods could be called on
abstract classes in the past" I will respect that, and as I said above, it
won't bother me.  

My only reason for persisting is to ensure that the argument I was making was understood before it
was dismissed.

-Mike

[1]  Ignoring there were technical issues with allowing untyped to be readonly, which could have
been gotten around somehow if the consensus was "They must be able to untyped."



Thread (71 messages)

« previous php.internals (#123926) next »