# [RFC] Abstract final classes

- Thread: https://externals.io/message/79211
- Original archive: https://news-web.php.net/php.internals/79211
- Started by guilhermeblanco@gmail.com on 2014-11-27T03:47:46+00:00
- Messages: 15
- RFC: Static class (Declined) — https://externals.io/rfc/static_class.md
- RFC: Abstract final classes / Static classes (Declined) — https://externals.io/rfc/abstract_final_class.md
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · RFCs at https://externals.io/rfc.md · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #79211 — guilhermeblanco@gmail.com — 2014-11-27T03:47:46+00:00

URL: https://externals.io/message/79211#79211

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

---

## #79212 — Marco Pivetta — 2014-11-27T03:58:47+00:00

URL: https://externals.io/message/79211#79212 · In reply to: #79211

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

---

## #79213 — Stanislav Malyshev — 2014-11-27T07:19:04+00:00

URL: https://externals.io/message/79211#79213 · In reply to: #79211

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

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

---

## #79219 — Lazare Inepologlou — 2014-11-27T10:35:10+00:00

URL: https://externals.io/message/79211#79219 · In reply to: #79211

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

---

## #79222 — Sebastian Krebs — 2014-11-27T11:57:33+00:00

URL: https://externals.io/message/79211#79222 · In reply to: #79211

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.
>
> https://wiki.php.net/rfc/abstract_final_class
>
>


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
>



-- 
github.com/KingCrunch

---

## #79226 — Rowan Collins — 2014-11-27T12:43:13+00:00

URL: https://externals.io/message/79211#79226 · In reply to: #79219

Lazare Inepologlou wrote on 27/11/2014 10:35:
> 2014-11-27 4:47 GMT+01:00 guilhermeblanco@gmail.com <
> guilhermeblanco@gmail.com>:
>
> > […]
> "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]

---

## #79227 — Ferenc Kovacs — 2014-11-27T13:10:02+00:00

URL: https://externals.io/message/79211#79227 · In reply to: #79226

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 <
> > […]
>
> 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

---

## #79228 — Rowan Collins — 2014-11-27T13:14:16+00:00

URL: https://externals.io/message/79211#79228 · In reply to: #79211

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.
>
> https://wiki.php.net/rfc/abstract_final_class

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]

---

## #79231 — guilhermeblanco@gmail.com — 2014-11-27T14:08:36+00:00

URL: https://externals.io/message/79211#79231 · In reply to: #79228

> 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.


> > […]
>
> 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:
>
> > […]
>
> The explanation of what exactly has been implemented could perhaps be
> expanded:
>
> > […]
> 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

---

## #79232 — Rowan Collins — 2014-11-27T15:06:00+00:00

URL: https://externals.io/message/79211#79232 · In reply to: #79231

guilhermeblanco@gmail.com wrote on 27/11/2014 14:08:
> > […]
>
> 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).


> > […]
> "static" class:
>
> > […]
> extended", and "final" means "can't be extended", so > combining the 
> two seems like a self-contradiction.
> > […]
> without sub-classing always seems a bit odd to me - it's as > though 
> only the constructor is really abstract, not the whole class.
> > […]
> something I've wanted.
>
> > […]
>
> 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]

---

## #79234 — guilhermeblanco@gmail.com — 2014-11-27T15:34:42+00:00

URL: https://externals.io/message/79211#79234 · In reply to: #79232

> 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 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.

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:
>
> > […]
>
> 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).
>
>
> > […]
>
> 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]
>
> --
> 
> 
>
>


-- 
Guilherme Blanco
MSN: guilhermeblanco@hotmail.com
GTalk: guilhermeblanco
Toronto - ON/Canada

---

## #79235 — Rowan Collins — 2014-11-27T15:49:05+00:00

URL: https://externals.io/message/79211#79235 · In reply to: #79234

guilhermeblanco@gmail.com wrote on 27/11/2014 15:34:
> > […]
> are final. Allowing a "static class" would allow you to
> > […]
> banning users from extending it (which is a completely
> > […]
>
> 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.

---

## #79252 — guilhermeblanco@gmail.com — 2014-11-27T20:38:14+00:00

URL: https://externals.io/message/79211#79252 · In reply to: #79235

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:
>
> > […]
>
> 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

---

## #79259 — Stanislav Malyshev — 2014-11-28T06:34:31+00:00

URL: https://externals.io/message/79211#79259 · In reply to: #79231

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

---

## #79389 — Josh Watzman — 2014-12-02T21:35:34+00:00

URL: https://externals.io/message/79211#79389 · In reply to: #79259

> > […]
> 
> 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.

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
