Hi,
I worked on an implementation of a somehow controversial concept that
exists in hack and C#: abstract final classes.
https://wiki.php.net/rfc/abstract_final_class
My motivation is to further expand class support to add modifiers (PPP -
public, protected, private). I added this change to initially segregate
grammar rules. It was an easy feature without extensive complexity and
covers some use-cases.
As a reference, here is the commit hash that added this feature to Hack:
https://github.com/facebook/hhvm/commit/faedfaf46b0deb859b0c20fb36a574be7a4f2f55
Cheers,
--
Guilherme Blanco
MSN: guilhermeblanco@hotmail.com
GTalk: guilhermeblanco
Toronto - ON/Canada
Except for the H1 on the RFC (needs to be updated), I can really see a lot
of cases where I needed this: badly.
On Nov 27, 2014 4:48 AM, "guilhermeblanco@gmail.com" <
guilhermeblanco@gmail.com> wrote:
Hi,
I worked on an implementation of a somehow controversial concept that
exists in hack and C#: abstract final classes.https://wiki.php.net/rfc/abstract_final_class
My motivation is to further expand class support to add modifiers (PPP -
public, protected, private). I added this change to initially segregate
grammar rules. It was an easy feature without extensive complexity and
covers some use-cases.As a reference, here is the commit hash that added this feature to Hack:
https://github.com/facebook/hhvm/commit/faedfaf46b0deb859b0c20fb36a574be7a4f2f55
Cheers,
--
Guilherme Blanco
MSN: guilhermeblanco@hotmail.com
GTalk: guilhermeblanco
Toronto - ON/Canada
Hi!
I worked on an implementation of a somehow controversial concept that
exists in hack and C#: abstract final classes.
In the RFC, I think one phrase needs clarification:
Currently, PHP developers' only resource is to create a final class with
a private constructor, leading to untestable and error prone code.
What is "error prone" in private __construct(); and how the RFC improves
the testability of such class?
The vote should be 2/3+1 surely as it is a language change.
My motivation is to further expand class support to add modifiers (PPP -
public, protected, private). I added this change to initially segregate
grammar rules. It was an easy feature without extensive complexity and
covers some use-cases.
I'm not sure I understand this part. Could you explain more?
Stas Malyshev
smalyshev@gmail.com
2014-11-27 4:47 GMT+01:00 guilhermeblanco@gmail.com <
guilhermeblanco@gmail.com>:
Hi,
I worked on an implementation of a somehow controversial concept that
exists in hack and C#: abstract final classes.https://wiki.php.net/rfc/abstract_final_class
My motivation is to further expand class support to add modifiers (PPP -
public, protected, private). I added this change to initially segregate
grammar rules. It was an easy feature without extensive complexity and
covers some use-cases.
"Abstract final" is a strange way to name it. What you want is a "static"
class:
-
The fact that one cannot initialise an abstract class is only a side
effect. Abstract classes are meant to be used for inheritance. -
Abstract static methods are not possible (one more reason why abstract is
a bad name). -
A "static" class does not have to be final, given the fact that PHP is
one of the few languages that offer a robust Late Static Binding.
Lazare INEPOLOGLOU
Ingénieur Logiciel
Lazare Inepologlou wrote on 27/11/2014 10:35:
2014-11-27 4:47 GMT+01:00 guilhermeblanco@gmail.com <
guilhermeblanco@gmail.com>:Hi,
I worked on an implementation of a somehow controversial concept that
exists in hack and C#: abstract final classes.https://wiki.php.net/rfc/abstract_final_class
My motivation is to further expand class support to add modifiers (PPP -
public, protected, private). I added this change to initially segregate
grammar rules. It was an easy feature without extensive complexity and
covers some use-cases."Abstract final" is a strange way to name it. What you want is a "static"
class:
The fact that one cannot initialise an abstract class is only a side
effect. Abstract classes are meant to be used for inheritance.Abstract static methods are not possible (one more reason why abstract is
a bad name).A "static" class does not have to be final, given the fact that PHP is
one of the few languages that offer a robust Late Static Binding.
This has always been my feeling. To me, "abstract" means "must be
extended", and "final" means "can't be extended", so combining the two
seems like a self-contradiction.
The fact that abstract classes allow static methods to be called without
sub-classing always seems a bit odd to me - it's as though only the
constructor is really abstract, not the whole class.
A "static" class, however, whether "final" or not, is definitely
something I've wanted.
Regards,
Rowan Collins
[IMSoP]
On Thu, Nov 27, 2014 at 1:43 PM, Rowan Collins rowan.collins@gmail.com
wrote:
Lazare Inepologlou wrote on 27/11/2014 10:35:
2014-11-27 4:47 GMT+01:00 guilhermeblanco@gmail.com <
Hi,
I worked on an implementation of a somehow controversial concept that
exists in hack and C#: abstract final classes.https://wiki.php.net/rfc/abstract_final_class
My motivation is to further expand class support to add modifiers (PPP -
public, protected, private). I added this change to initially segregate
grammar rules. It was an easy feature without extensive complexity and
covers some use-cases."Abstract final" is a strange way to name it. What you want is a
"static"
class:
The fact that one cannot initialise an abstract class is only a side
effect. Abstract classes are meant to be used for inheritance.Abstract static methods are not possible (one more reason why abstract
is
a bad name).A "static" class does not have to be final, given the fact that PHP is
one of the few languages that offer a robust Late Static Binding.This has always been my feeling. To me, "abstract" means "must be
extended", and "final" means "can't be extended", so combining the two
seems like a self-contradiction.The fact that abstract classes allow static methods to be called without
sub-classing always seems a bit odd to me - it's as though only the
constructor is really abstract, not the whole class.A "static" class, however, whether "final" or not, is definitely something
I've wanted.Regards,
Rowan Collins
[IMSoP]--
for the record I also brought up this argument (abstract and final being
contradicting ideas) in the pull request comments(before this thread was
created).
--
Ferenc Kovács
@Tyr43l - http://tyrael.hu
Hi,
2014-11-27 4:47 GMT+01:00 guilhermeblanco@gmail.com <
guilhermeblanco@gmail.com>:
Hi,
I worked on an implementation of a somehow controversial concept that
exists in hack and C#: abstract final classes.
The example is a little bit misleading: Instead of a new concept you can
use functions, right?
Regards,
Sebastian
My motivation is to further expand class support to add modifiers (PPP -
public, protected, private). I added this change to initially segregate
grammar rules. It was an easy feature without extensive complexity and
covers some use-cases.As a reference, here is the commit hash that added this feature to Hack:
https://github.com/facebook/hhvm/commit/faedfaf46b0deb859b0c20fb36a574be7a4f2f55
Cheers,
--
Guilherme Blanco
MSN: guilhermeblanco@hotmail.com
GTalk: guilhermeblanco
Toronto - ON/Canada
guilhermeblanco@gmail.com wrote on 27/11/2014 03:47:
I worked on an implementation of a somehow controversial concept that
exists in hack and C#: abstract final classes.
The explanation of what exactly has been implemented could perhaps be
expanded:
Change language scanner to accept abstract final class constructor,
and subsequently restricting to only static members.
Does this mean that the following will be flagged as invalid? If so,
what error message will be raised?
abstract final class Foo {
abstract public function doTheImpossible();
}
This class is technically valid as an abstract class, but the addition
of the "final" keyword makes the abstract method declaration completely
meaningless, since it can never be implemented.
Regards,
Rowan Collins
[IMSoP]
In the RFC, I think one phrase needs clarification:
Currently, PHP developers' only resource is to create a final class with
a private constructor, leading to untestable and error prone code.What is "error prone" in private __construct(); and how the RFC improves
the testability of such class?
The reason comes not to the construct method itself, but to other
implemented methods.
By forgetting "static" in any of your declared methods, you get no parse
error and gives you 2 possibilities:
- With
E_STRICT
enabled: Fatal error when non-static method is being
statically called. You'll only get this at runtime, leading to potentially
error prone. Now the testability come that with this addiction, you get a
fatal error, which is easily fixable at compile time, not runtime. - With
E_STRICT
disabled: You get a warning on php log and everything works
(which is a huge wtf mode).
The vote should be 2/3+1 surely as it is a language change.
Sure, I can update the RFC to clarify this.
My motivation is to further expand class support to add modifiers (PPP -
public, protected, private). I added this change to initially segregate
grammar rules. It was an easy feature without extensive complexity and
covers some use-cases.I'm not sure I understand this part. Could you explain more?
My end goal is to add class visibility to PHP. Unfortunately, I was forced
to change bison grammar, reduce one ACC flag, so I could add this support.
While doing that, I realized that "abstract final" was an easy support to
add, since the entire engine already deals with both cases smoothly. All I
had to do was remove the compiler check that was fataling and add necessary
checks for class members.
I stopped to code class visibility so we could vote on small incremental
feature addictions. https://github.com/php/php-src/pull/911 is a
requirement for class visibility too, because I'll move the ZEND_ACC_TRAIT
to a proper binary value and address builtin_functions accordingly. I saw
not linear room for a new flag, so I worked on reusing FINAL and now I
worked on grammar support as part of this RFC's patch. Next patch will add
PPP (public, protected, private) support to classes.
"Abstract final" is a strange way to name it. What you want is a "static"
class:
This has always been my feeling. To me, "abstract" means "must be
extended", and "final" means "can't be extended", so > combining the two
seems like a self-contradiction.The fact that abstract classes allow static methods to be called without
sub-classing always seems a bit odd to me - it's as > though only the
constructor is really abstract, not the whole class.A "static" class, however, whether "final" or not, is definitely
something I've wanted.
for the record I also brought up this argument (abstract and final being
contradicting ideas) in the pull request comments(before this thread was
created).
No, because conceptually, a static something means that subsequent calls
always return same value. A static class means a singleton, not what this
patch proposal.
You have to remember:
- "abstract" means it cannot be instantiated directly
- "final" means it cannot be extended
The example is a little bit misleading: Instead of a new concept you can
use functions, right?
Yes, but allowing namespace level functions does not give you property
level functions.
Does this mean that the following will be flagged as invalid? If so, what
error message will be raised?abstract final class Foo {
abstract public function doTheImpossible();
}This class is technically valid as an abstract class, but the addition of
the "final" keyword makes the abstract method
declaration completely meaningless, since it can never be implemented.
You are correct. Methods cannot be declared abstract if you have an
"abstract final". They must also be static. I added these checks together
with static properties here:
- Properties:
https://github.com/php/php-src/pull/923/files#diff-3a8139128d4026ce0cb0c86beba4e6b9R4251 - Methods:
https://github.com/php/php-src/pull/923/files#diff-3a8139128d4026ce0cb0c86beba4e6b9R3936
I'm able to expand the RFC in any way you may like before entering voting
phase... just mention to me and I do it! =)
Cheers,
On Thu, Nov 27, 2014 at 8:14 AM, Rowan Collins rowan.collins@gmail.com
wrote:
guilhermeblanco@gmail.com wrote on 27/11/2014 03:47:
I worked on an implementation of a somehow controversial concept that
exists in hack and C#: abstract final classes.The explanation of what exactly has been implemented could perhaps be
expanded:Change language scanner to accept abstract final class constructor, and
subsequently restricting to only static members.Does this mean that the following will be flagged as invalid? If so, what
error message will be raised?abstract final class Foo {
abstract public function doTheImpossible();
}This class is technically valid as an abstract class, but the addition of
the "final" keyword makes the abstract method declaration completely
meaningless, since it can never be implemented.Regards,
Rowan Collins
[IMSoP]--
--
Guilherme Blanco
MSN: guilhermeblanco@hotmail.com
GTalk: guilhermeblanco
Toronto - ON/Canada
guilhermeblanco@gmail.com wrote on 27/11/2014 14:08:
In the RFC, I think one phrase needs clarification:
Currently, PHP developers' only resource is to create a final class with
a private constructor, leading to untestable and error prone code.What is "error prone" in private __construct(); and how the RFC improves
the testability of such class?The reason comes not to the construct method itself, but to other
implemented methods.
By forgetting "static" in any of your declared methods, you get no
parse error and gives you 2 possibilities:
- With
E_STRICT
enabled: Fatal error when non-static method is being
statically called. You'll only get this at runtime, leading to
potentially error prone. Now the testability come that with this
addiction, you get a fatal error, which is easily fixable at compile
time, not runtime.- With
E_STRICT
disabled: You get a warning on php log and everything
works (which is a huge wtf mode).
This is true of classes intended to be static whether or not they are
final. Allowing a "static class" would allow you to enforce that all
methods (and properties) must be static without banning users from
extending it (which is a completely orthogonal decision).
"Abstract final" is a strange way to name it. What you want is a
"static" class:This has always been my feeling. To me, "abstract" means "must be
extended", and "final" means "can't be extended", so > combining the
two seems like a self-contradiction.The fact that abstract classes allow static methods to be called
without sub-classing always seems a bit odd to me - it's as > though
only the constructor is really abstract, not the whole class.A "static" class, however, whether "final" or not, is definitely
something I've wanted.for the record I also brought up this argument (abstract and final being
contradicting ideas) in the pull request comments(before this thread was
created).No, because conceptually, a static something means that subsequent
calls always return same value. A static class means a singleton, not
what this patch proposal.
You have to remember:
- "abstract" means it cannot be instantiated directly
- "final" means it cannot be extended
That's not how they're interpreted with regard to methods, unless I'm
missing something:
- "abstract function" means a method which must be implemented by a
sub-class - "static function" means a method with no access to $this, operating
outside of any instance
Taking those behaviours for class definitions leads to the
interpretation that seems natural to me:
- "abstract class" means a class which must be extended before use, and
may contain abstract methods - "static class" would mean a class which can never be used to create an
instance, and can contain only static methods
"final" is orthogonal to these, and means that a class cannot be
extended; under this interpretation, "abstract final" is a
contradiction, but "static final" makes perfect sense.
Regards,
Rowan Collins
[IMSoP]
This is true of classes intended to be static whether or not they are
final. Allowing a "static class" would allow you to
enforce that all methods (and properties) must be static without banning
users from extending it (which is a completely
orthogonal decision).
So if I still want to not allow anyone to extend it, I would then have a
final static class. Remember, I don't want people to change methods'
visibility.
How does that become different from final abstract? I know you answered
below... =)
That's not how they're interpreted with regard to methods, unless I'm
missing something:
- "abstract function" means a method which must be implemented by a
sub-class- "static function" means a method with no access to $this, operating
outside of any instanceTaking those behaviours for class definitions leads to the interpretation
that seems natural to me:
- "abstract class" means a class which must be extended before use, and
may contain abstract methods- "static class" would mean a class which can never be used to create an
instance, and can contain only static methods"final" is orthogonal to these, and means that a class cannot be
extended; under this interpretation, "abstract final" is a
contradiction, but "static final" makes perfect sense.
The piece it's missing in "static" definition: there can only be one
instance of something.
I'd argue that declaring a class static is the same as declaring a
singleton. Multiple object instantiations over a static class would return
always same instance.
Now taking this into consideration, I'd modify your concepts to the
following:
- "abstract function" means a method which must be implemented by a
sub-class - "static function" means a method with no access to $this, operating
outside of any instance. This means it's bound to class entry, which can
only have one possibility to be called: statically and given same
parameters it should return same output, unless normal flow controlled by a
static variable.
I'm more than happy to change "abstract" to "static" if it's the desire of
everybody. That would match C# implementation as defined here:
http://msdn.microsoft.com/en-us/library/79b3xss3.aspx Now it's funny that
C# also accepts "abstract final" with the same idea/concept of their
documentation of static classes. #weird
[]s,
On Thu, Nov 27, 2014 at 10:06 AM, Rowan Collins rowan.collins@gmail.com
wrote:
guilhermeblanco@gmail.com wrote on 27/11/2014 14:08:
In the RFC, I think one phrase needs clarification:
Currently, PHP developers' only resource is to create a final class with
a private constructor, leading to untestable and error prone code.What is "error prone" in private __construct(); and how the RFC improves
the testability of such class?The reason comes not to the construct method itself, but to other
implemented methods.
By forgetting "static" in any of your declared methods, you get no parse
error and gives you 2 possibilities:
- With
E_STRICT
enabled: Fatal error when non-static method is being
statically called. You'll only get this at runtime, leading to potentially
error prone. Now the testability come that with this addiction, you get a
fatal error, which is easily fixable at compile time, not runtime.- With
E_STRICT
disabled: You get a warning on php log and everything
works (which is a huge wtf mode).This is true of classes intended to be static whether or not they are
final. Allowing a "static class" would allow you to enforce that all
methods (and properties) must be static without banning users from
extending it (which is a completely orthogonal decision)."Abstract final" is a strange way to name it. What you want is a
"static" class:This has always been my feeling. To me, "abstract" means "must be
extended", and "final" means "can't be extended", so > combining the two
seems like a self-contradiction.The fact that abstract classes allow static methods to be called
without sub-classing always seems a bit odd to me - it's as > though only
the constructor is really abstract, not the whole class.A "static" class, however, whether "final" or not, is definitely
something I've wanted.for the record I also brought up this argument (abstract and final being
contradicting ideas) in the pull request comments(before this thread was
created).No, because conceptually, a static something means that subsequent calls
always return same value. A static class means a singleton, not what this
patch proposal.
You have to remember:
- "abstract" means it cannot be instantiated directly
- "final" means it cannot be extended
That's not how they're interpreted with regard to methods, unless I'm
missing something:
- "abstract function" means a method which must be implemented by a
sub-class- "static function" means a method with no access to $this, operating
outside of any instanceTaking those behaviours for class definitions leads to the interpretation
that seems natural to me:
- "abstract class" means a class which must be extended before use, and
may contain abstract methods- "static class" would mean a class which can never be used to create an
instance, and can contain only static methods"final" is orthogonal to these, and means that a class cannot be extended;
under this interpretation, "abstract final" is a contradiction, but "static
final" makes perfect sense.Regards,
Rowan Collins
[IMSoP]--
--
Guilherme Blanco
MSN: guilhermeblanco@hotmail.com
GTalk: guilhermeblanco
Toronto - ON/Canada
guilhermeblanco@gmail.com wrote on 27/11/2014 15:34:
This is true of classes intended to be static whether or not they
are final. Allowing a "static class" would allow you to
enforce that all methods (and properties) must be static without
banning users from extending it (which is a completely
orthogonal decision).So if I still want to not allow anyone to extend it, I would then have
a final static class. Remember, I don't want people to change methods'
visibility.
Yep, that's the idea. I see no reason, particularly with Late Static
Binding, that it shouldn't be possible to have a static class which can
be extended by a static sub-class, if that fits a particular use case.
Ok... so if I update the RFC to be "static class", does that make everybody
happy?
I mainly wanna get this forward thinking trend... =)
On Thu, Nov 27, 2014 at 10:49 AM, Rowan Collins rowan.collins@gmail.com
wrote:
guilhermeblanco@gmail.com wrote on 27/11/2014 15:34:
This is true of classes intended to be static whether or not they are
final. Allowing a "static class" would allow you to
enforce that all methods (and properties) must be static without
banning users from extending it (which is a completely
orthogonal decision).So if I still want to not allow anyone to extend it, I would then have a
final static class. Remember, I don't want people to change methods'
visibility.Yep, that's the idea. I see no reason, particularly with Late Static
Binding, that it shouldn't be possible to have a static class which can be
extended by a static sub-class, if that fits a particular use case.--
--
Guilherme Blanco
MSN: guilhermeblanco@hotmail.com
GTalk: guilhermeblanco
Toronto - ON/Canada
Hi!
By forgetting "static" in any of your declared methods, you get no parse
error and gives you 2 possibilities:
- With
E_STRICT
enabled: Fatal error when non-static method is being
statically called. You'll only get this at runtime, leading to potentially
error prone. Now the testability come that with this addiction, you get a
fatal error, which is easily fixable at compile time, not runtime.
I don't see how it matters for testability - sure, if you don't test
your functions, you don't see the errors, but that's just best practice.
Also, since PHP is not a compiled language, practical difference between
"compile time" and "runtime" does not really exist.
- With
E_STRICT
disabled: You get a warning on php log and everything works
(which is a huge wtf mode).
Not everything, your functions still do not. If you write a function and
put it in production without ever trying to run it even once, that's
something that needs to be fixed (and you could as well have made a typo
in a function name or written whille() - there are a lot of errors that
one can make and PHP does not catch, especially if you never run your
code). Otherwise, the error is immediately obvious.
My end goal is to add class visibility to PHP. Unfortunately, I was forced
I'm not sure how it is related, but if it's not directly connected then
since that RFC does not exist AFAIK I don't think it can be an argument
for this one. If it is directly connected then maybe it could wait for
that RFC but then connection needs to be explained.
No, because conceptually, a static something means that subsequent calls
always return same value. A static class means a singleton, not what this
I'm not sure where it comes from - static function definitely does not
return same value on each call. Neither do static variables (which are
just class variables, but not immutable) or static closures (which are
just unbound closures). The only case where it is kind of true is static
variable in function, if you replace "value" by "variable", but this is
only because the syntax was borrowed from C. So static in PHP means a
lot of thing but the general gist is "not subject to current scope".
Where the "static class means a singleton" came from? Could you explain?
You are correct. Methods cannot be declared abstract if you have an
"abstract final". They must also be static. I added these checks together
To me, it just feels a bit unnatural. So you have abstract class, which
usually has abstract methods. Then you have "abstract final" class which
can not have abstract methods, but instead should have "static" methods.
This just sounds a bit weird to me - adding "final" to description of
the class completely changes all the rules in very unexpected direction.
--
Stas Malyshev
smalyshev@gmail.com
You are correct. Methods cannot be declared abstract if you have an
"abstract final". They must also be static. I added these checks togetherTo me, it just feels a bit unnatural. So you have abstract class, which
usually has abstract methods. Then you have "abstract final" class which
can not have abstract methods, but instead should have "static" methods.
This just sounds a bit weird to me - adding "final" to description of
the class completely changes all the rules in very unexpected direction.
What does it mean to have an abstract static function? Abstract (non-static) functions make sense for abstract classes -- since you cannot instantiate the abstract class, you know that the instantiable subclass that you actually have an instance of must have implemented the method, so it's safe to call. But you can call static methods on abstract classes, and so you have no guarantee that the abstract static method exists -- and you need to be very careful with LSB to actually call it correctly anyways.
Does this mean that static classes with abstract methods (or abstract static classes, or however this ends up working out syntactically) won't be allowed to have static methods called on them directly? How do you make sure that the methods in them do the right LSB stuff to call the abstract static functions correctly?
Inheritance semantics for static classes also get messy when you start dealing with traits. As a quick example, the current proposal only allows static classes to inherit from other static classes... but where do traits fit in here? Only traits with only static methods are allowed to be included? This could lead to some very annoying refactoring scenarios where changing a trait that is used in several places leads to errors with static classes... traits bring up many of the same issues as multiple inheritance, and I think you'll have some of those issues here.
All of the above is the crux of the issue of why Hack went with "abstract final" and not anything else. Abstract does not mean "must be subclassed" -- you can have an abstract class with no subclasses and still call static methods on it; this is perfectly meaningful, and is at least how I emulated "abstract final" before Hack got the feature. Abstract means "cannot be instantiated" (and, since it cannot be instantiated, may contain instance methods with empty bodies, i.e., abstract methods). Then final means "cannot be subclassed" -- so the two together means you have a class that has no instances itself, and cannot be subclasses, so you can never have an object of that type. The use cases for being able to override such a class are questionable at best, as above.
This really is just the combination of two existing class modifiers -- no need to introduce a new "static" modifier. And it leads to lots of interesting issues, as above.
Josh Watzman