Chatter on the Interface Default Methods RFC has been quiet for
the past 6 days, and the feature freeze deadline is fast approaching
for PHP 8.3, so I'm moving this to vote. It'll be open for two weeks
as usual.
Thanks to everyone who discussed weaknesses in the RFC during the
discussion phase.
On Sun, Jul 2, 2023 at 9:11 PM Levi Morrison morrison.levi@gmail.com
wrote:
Chatter on the Interface Default Methods RFC has been quiet for
the past 6 days, and the feature freeze deadline is fast approaching
for PHP 8.3, so I'm moving this to vote. It'll be open for two weeks
as usual.Thanks to everyone who discussed weaknesses in the RFC during the
discussion phase.--
To unsubscribe, visit: https://www.php.net/unsub.php
That's wonderful news Levi! Good luck to us all on this RFC!!
--
Marco Deleu
Chatter on the Interface Default Methods RFC has been quiet for
the past 6 days, and the feature freeze deadline is fast approaching
for PHP 8.3, so I'm moving this to vote. It'll be open for two weeks
as usual.Thanks to everyone who discussed weaknesses in the RFC during the
discussion phase.
I’m probably going to vote “yes” on this, but since the property accessors RFC won’t be ready for 8.3,1 and that RFC covers use of properties in interfaces, how useful will interface default methods be without interface properties?
Cheers,
Ben
Chatter on the Interface Default Methods RFC has been quiet for
the past 6 days, and the feature freeze deadline is fast approaching
for PHP 8.3, so I'm moving this to vote. It'll be open for two weeks
as usual.Thanks to everyone who discussed weaknesses in the RFC during the
discussion phase.I’m probably going to vote “yes” on this, but since the property accessors RFC won’t be ready for 8.3,1 and that RFC covers use of properties in interfaces, how useful will interface default methods be without interface properties?
Plenty useful, I think. Interfaces deal with abstractions, so there
are often things you can do without having state. Java's interfaces
don't allow properties, for instance, and they still have this
feature.
As an example, this poor-man Sequence interface works, because the
behavior and state for next
is provided by the implementer:
<?php
interface Sequence {
// return null to indicate the end of sequence
function `next()`;
function fold($initial, callable $f) {
$reduction = $initial;
while (($next = $this->next()) !== null) {
$reduction = $f($reduction, $next);
}
return $reduction;
}
function reduce(callable $f) {
$next = $this->next();
return $next !== null
? $this->fold($next, $f)
: null;
}
function into_array_list(): array {
$array = [];
while (($next = $this->next()) !== null) {
$array[] = $next;
}
return $array;
}
}
final class IteratorSequence
implements Sequence
{
function __construct(private Iterator $iter) {
$this->iter->rewind();
}
function `next()` {
$iter = $this->iter;
if ($iter->valid()) {
$next = $iter->current();
$iter->next();
return $next;
}
return null;
}
}
function xrange($begin, $end) {
$i = $begin;
while ($i < $end) {
yield $i++;
}
}
$seq = new IteratorSequence(xrange(1, 10));
var_export($seq->into_array_list());
echo PHP_EOL;
I’m probably going to vote “yes” on this, but since the property accessors RFC won’t be ready for 8.3,[1] and that RFC covers use of properties in interfaces, how useful will interface default methods be without interface properties?
Plenty useful, I think. Interfaces deal with abstractions, so there
are often things you can do without having state. Java's interfaces
don't allow properties, for instance, and they still have this
feature.As an example, this poor-man Sequence interface works, because the
behavior and state fornext
is provided by the implementer:
Thanks for the response. This makes perfect sense to me now.
Cheers,
Ben
Am 03.07.23 um 02:11 schrieb Levi Morrison:
Chatter on the Interface Default Methods RFC has been quiet for
the past 6 days, and the feature freeze deadline is fast approaching
for PHP 8.3, so I'm moving this to vote. It'll be open for two weeks
as usual.Thanks to everyone who discussed weaknesses in the RFC during the
discussion phase.
I've voted "no" on this RFC for one simple reason:
For me an interface is about the abstraction of a contract. It defines
how different parts of code interact with one another without having to
know about the implementation.
With this RFC we are adding implementation details to the abstraction.
That requires knowledge about the implementation of different parts of
the code. Which we do not have when defining an interface.
If we have this knowledge then we are not defining an interface but an
implementation were some implementation details need to be overwritten
depending on business-logic. That is what an abstract class is there for.
And TBH: I do not really care whether there are other languages that
think that is a good idea: For me it is not.
If one needs default implementations of an interface: Use Traits. But
leave the contract abstract. ANd if you need to declare some methods to
be implemented while others are fixed: Use abstract classes.
My 0.02€
Cheers
Andreas
,,,
(o o)
+---------------------------------------------------------ooO-(_)-Ooo-+
| Andreas Heigl |
| mailto:andreas@heigl.org N 50°22'59.5" E 08°23'58" |
| https://andreas.heigl.org https://hei.gl/where |
| https://hei.gl/pubkeyandreas |
+---------------------------------------------------------------------+
Hi Andreas,
pon., 3 lip 2023 o 06:33 Andreas Heigl andreas@heigl.org napisał(a):
Am 03.07.23 um 02:11 schrieb Levi Morrison:
Chatter on the Interface Default Methods RFC has been quiet for
the past 6 days, and the feature freeze deadline is fast approaching
for PHP 8.3, so I'm moving this to vote. It'll be open for two weeks
as usual.Thanks to everyone who discussed weaknesses in the RFC during the
discussion phase.I've voted "no" on this RFC for one simple reason:
For me an interface is about the abstraction of a contract. It defines
how different parts of code interact with one another without having to
know about the implementation.With this RFC we are adding implementation details to the abstraction.
That requires knowledge about the implementation of different parts of
the code. Which we do not have when defining an interface.
I disagree, look at the example I presented in my other response,
one method can use another to provide a default method which you'd be
including via trait
in every implementing class because as it only uses another interface
method.
This means that you don't need to know anything about the implementation
itself at all.
You're free to use other interface methods and don't need any properties or
implementation details.
Cheers,
Michał Marcin Brzuchalski
Hi
Chatter on the [Interface Default Methods RFC][1] has been quiet for
the past 6 days, and the feature freeze deadline is fast approaching
for PHP 8.3, so I'm moving this to vote. It'll be open for two weeks
as usual.
I'm not really sold on the proposal in the first place, but I find it
incredibly problematic that there were non-trivial changes to the RFC
text just 4 minutes before voting started and having the justification
"it will be easier to change if bad".
Combined with the phrasing of the email I'm replying to, it looks like
this proposal is attempted to be forced into PHP 8.3 for some reason,
without fully thinking it through / without allowing an in-depth
discussion. This is probably going to bite in the longer term.
Best regards
Tim Düsterhus
Hi
Chatter on the [Interface Default Methods RFC][1] has been quiet for
the past 6 days, and the feature freeze deadline is fast approaching
for PHP 8.3, so I'm moving this to vote. It'll be open for two weeks
as usual.I'm not really sold on the proposal in the first place, but I find it
incredibly problematic that there were non-trivial changes to the RFC
text just 4 minutes before voting started and having the justification
"it will be easier to change if bad".Combined with the phrasing of the email I'm replying to, it looks like
this proposal is attempted to be forced into PHP 8.3 for some reason,
without fully thinking it through / without allowing an in-depth
discussion. This is probably going to bite in the longer term.Best regards
Tim Düsterhus--
To unsubscribe, visit: https://www.php.net/unsub.php
I suppose different people will think different things about what
'trivial' means, but the main changes were announced 6 days earlier on
the mailing list, and there was no discussion about it all. I consider
that to be fine. I also do not consider that to be hurried.
Hi Levi,
pon., 3 lip 2023 o 02:11 Levi Morrison morrison.levi@gmail.com napisał(a):
Chatter on the Interface Default Methods RFC has been quiet for
the past 6 days, and the feature freeze deadline is fast approaching
for PHP 8.3, so I'm moving this to vote. It'll be open for two weeks
as usual.Thanks to everyone who discussed weaknesses in the RFC during the
discussion phase.
I voted "yes", my personal use case waits for this feature. My use
case example:
https://gist.github.com/brzuchal/89e9481bbd34a6ce3d95a68eabff038b
With interface default methods I'd no longer need traits that implement a
single or in rare cases 2 methods that
use their respective methods returning objects and iterate in Generator
fashion over a paginated result set.
This is not an issue if there is one implementation of the interface but
when I decorate to apply some:
- caching
- logging
- failover
then the trait has to be attached to every class besides that it has to
exist which is an additional symbol here.
Cheers,
Michał Marcin Brzuchalski
Le 03/07/2023 à 13:32, Michał Marcin Brzuchalski a écrit :
I voted "yes", my personal use case waits for this feature. My use
case example:https://gist.github.com/brzuchal/89e9481bbd34a6ce3d95a68eabff038b
With interface default methods I'd no longer need traits that implement a
single or in rare cases 2 methods that
use their respective methods returning objects and iterate in Generator
fashion over a paginated result set.
This is not an issue if there is one implementation of the interface but
when I decorate to apply some:
- caching
- logging
- failover
then the trait has to be attached to every class besides that it has to
exist which is an additional symbol here.Cheers,
Michał Marcin Brzuchalski
Please everyone yes to this !
I use Symfony daily, and the SomethingAwareInterface /
SomethingAwareTrait is very annoying, by having default method
implementations on interfaces, it would remove the use of having traits
at all. Everything would be much easier to read and write.
LoggerAwareInterface would no longer require us to use LoggerAwareTrait
on every class, etc...
This is kind of sugar candy I'd really love.
Best regards,
--
Pierre
pon., 3 lip 2023 o 13:50 Pierre pierre-php@processus.org napisał(a):
Le 03/07/2023 à 13:32, Michał Marcin Brzuchalski a écrit :
I voted "yes", my personal use case waits for this feature. My use
case example:https://gist.github.com/brzuchal/89e9481bbd34a6ce3d95a68eabff038b
With interface default methods I'd no longer need traits that implement a
single or in rare cases 2 methods that
use their respective methods returning objects and iterate in Generator
fashion over a paginated result set.
This is not an issue if there is one implementation of the interface but
when I decorate to apply some:
- caching
- logging
- failover
then the trait has to be attached to every class besides that it has to
exist which is an additional symbol here.Cheers,
Michał Marcin BrzuchalskiPlease everyone yes to this !
I use Symfony daily, and the SomethingAwareInterface /
SomethingAwareTrait is very annoying, by having default method
implementations on interfaces, it would remove the use of having traits
at all. Everything would be much easier to read and write.
I agree, there are two interfaces that always require adding a trait in
Symfony.
These are NormalizerAwareInterface, DenormalizerAwareInterface
They always require including NormalizerAwareTrait, DenormalizerAwareTrait.
With this feature none of the above traits would no longer be required and
the interface use would be less confusing.
Cheers,
Michał Marcin Brzuchalski
Hey Michał
Hi Levi,
pon., 3 lip 2023 o 02:11 Levi Morrison morrison.levi@gmail.com napisał(a):
Chatter on the Interface Default Methods RFC has been quiet for
the past 6 days, and the feature freeze deadline is fast approaching
for PHP 8.3, so I'm moving this to vote. It'll be open for two weeks
as usual.Thanks to everyone who discussed weaknesses in the RFC during the
discussion phase.I voted "yes", my personal use case waits for this feature. My use
case example:https://gist.github.com/brzuchal/89e9481bbd34a6ce3d95a68eabff038b
I've added two already possible solutions to that as comments.
With interface default methods I'd no longer need traits that implement a
single or in rare cases 2 methods that
use their respective methods returning objects and iterate in Generator
fashion over a paginated result set.
This is not an issue if there is one implementation of the interface but
when I decorate to apply some:
- caching
- logging
- failover
That requires that you are in control over both the interface AND the
implementation. In which case you probably do not need an interface and
the Trait would be enough (using abstract public function
in traits
works after all)
So you could even skip the implements part.
As the interface should be designed specifically to be
implementation-agnostic, adding implementation to the interface is
counter-productive.
Adding abstract methods to a trait and then just adding the traits is no
issue at all especially when you are in control of the interface AND the
implementation.
When you are NOT in control of the interface... well, you can't expect
to have a default implementation and I am already looking forward to the
complaints that it is great to have a default implementation, but not
that one.
There is a reason why the respective construct in Rust (which was
mentioned in the RFC) is called a Trait and not an Interface.
So to decouple the contract from the implementation it is necessary that
no implementation is part of the contract.
then the trait has to be attached to every class besides that it has to
exist which is an additional symbol here.
Stop using implements
at all and solely rely on use
.
My 0.02€
Cheers
Andreas
,,,
(o o)
+---------------------------------------------------------ooO-(_)-Ooo-+
| Andreas Heigl |
| mailto:andreas@heigl.org N 50°22'59.5" E 08°23'58" |
| https://andreas.heigl.org |
+---------------------------------------------------------------------+
| https://hei.gl/appointmentwithandreas |
+---------------------------------------------------------------------+
| GPG-Key: https://hei.gl/keyandreasheiglorg |
+---------------------------------------------------------------------+
pon., 3 lip 2023 o 14:26 Andreas Heigl andreas@heigl.org napisał(a):
Hey Michał
Hi Levi,
pon., 3 lip 2023 o 02:11 Levi Morrison morrison.levi@gmail.com
napisał(a):Chatter on the Interface Default Methods RFC has been quiet for
the past 6 days, and the feature freeze deadline is fast approaching
for PHP 8.3, so I'm moving this to vote. It'll be open for two weeks
as usual.Thanks to everyone who discussed weaknesses in the RFC during the
discussion phase.I voted "yes", my personal use case waits for this feature. My use
case example:https://gist.github.com/brzuchal/89e9481bbd34a6ce3d95a68eabff038b
I've added two already possible solutions to that as comments.
With interface default methods I'd no longer need traits that implement a
single or in rare cases 2 methods that
use their respective methods returning objects and iterate in Generator
fashion over a paginated result set.
This is not an issue if there is one implementation of the interface but
when I decorate to apply some:
- caching
- logging
- failover
That requires that you are in control over both the interface AND the
implementation. In which case you probably do not need an interface and
the Trait would be enough (usingabstract public function
in traits
works after all)So you could even skip the implements part.
As the interface should be designed specifically to be
implementation-agnostic, adding implementation to the interface is
counter-productive.Adding abstract methods to a trait and then just adding the traits is no
issue at all especially when you are in control of the interface AND the
implementation.When you are NOT in control of the interface... well, you can't expect
to have a default implementation and I am already looking forward to the
complaints that it is great to have a default implementation, but not
that one.There is a reason why the respective construct in Rust (which was
mentioned in the RFC) is called a Trait and not an Interface.So to decouple the contract from the implementation it is necessary that
no implementation is part of the contract.then the trait has to be attached to every class besides that it has to
exist which is an additional symbol here.Stop using
implements
at all and solely rely onuse
.
I use an interface for mocks in unit tests.
A default interface method allows me to remove some traits which are not my
favorite and I'd like to remove them all.
Turning the interface into an abstract class adds an inheritance that I
want to avoid.
Given that, it true is that it is possible to solve the problem differently
but not without side effects (either lack of contract or inheritance).
Cheers,
Michał Marcin Brzuchalski
Stop using
implements
at all and solely rely onuse
.My 0.02€
Cheers
Andreas
A Trait is not part of the Type system, it's not type-hintable, it's not
mockable, it's harder to do code review (a Trait was modified, what gets
impacted?). A trait is just an "easy" way to copy/paste code while hiding
away the code that is being copy/pasted. To be honest here, a Trait is
something that I wouldn't miss if it was deprecated, although I know that's
just wishful thinking. An interface default implementation on the other
hand is extremely powerful and clear. If you're not happy with the default
implementation, just write your own, otherwise less code to write and a
better type system at the end.
--
Marco Deleu
a Trait was modified, what gets impacted?
Is this not already the case for all tightly coupled code? This RFC
proposes to make the least-coupled code in PHP more coupled, so soon,
you'll be able to say the same for interfaces (if this passes).
I don't understand this RFC. Symfony is a mess in that a class
requires an interface, even if there is only one implementation. PHP
shouldn't fix that, Symfony should rethink how they're doing
inheritance.
Abstract classes solve this problem perfectly. It's part of the type
system, it's type-hintable, it's mockable, and it's pretty easy to see
what inherits it as people who inherit it already know what the base
behavior was when they wrote the code.
Hi Robert,
wt., 11 lip 2023 o 14:54 Robert Landers landers.robert@gmail.com
napisał(a):
...
Abstract classes solve this problem perfectly. It's part of the type
system, it's type-hintable, it's mockable, and it's pretty easy to see
what inherits it as people who inherit it already know what the base
behavior was when they wrote the code.
Not exactly, How you wanna solve by abstract class two interfaces
which can be implemented using let's say two traits - let's say
interface Foo {
public function foo(): string;
}
trait HasFoo {
public function foo(): string { return 'foo'; }
}
interface Bar {
public function bar(): bool;
}
traitHasBar {
public function bar(): bool { return true; }
}
Now I can need to implement Foo or Bar separately or together.
Using abstract class that would require 3 abstract classes: Foo, Bar, and
FooWithBar.
With this RFC that would require just two interfaces with default methods.
Now you can easily see how bad this goes if you wanna add 3rd interface.
Cheers,
Michał Marcin Brzuchalski
On Tue, Jul 11, 2023 at 10:54 AM Michał Marcin Brzuchalski <
michal.brzuchalski@gmail.com> wrote:
Hi Robert,
wt., 11 lip 2023 o 14:54 Robert Landers landers.robert@gmail.com
napisał(a):...
Abstract classes solve this problem perfectly. It's part of the type
system, it's type-hintable, it's mockable, and it's pretty easy to see
what inherits it as people who inherit it already know what the base
behavior was when they wrote the code.Not exactly, How you wanna solve by abstract class two interfaces
which can be implemented using let's say two traits - let's sayinterface Foo {
public function foo(): string;
}
trait HasFoo {
public function foo(): string { return 'foo'; }
}
interface Bar {
public function bar(): bool;
}
traitHasBar {
public function bar(): bool { return true; }
}Now I can need to implement Foo or Bar separately or together.
Using abstract class that would require 3 abstract classes: Foo, Bar, and
FooWithBar.
With this RFC that would require just two interfaces with default methods.Now you can easily see how bad this goes if you wanna add 3rd interface.
Cheers,
Michał Marcin Brzuchalski
I second this. Imagine a class extends LogAwareAbstractClass. It makes no
sense to the type system and it makes it impossible to extend something
that actually is part of the domain definition. Interface Default
Implementation is an elegant solution that doesn't change the state of PHP
while still making things easier and convenient to manage.
--
Marco Deleu
Not exactly, How you wanna solve by abstract class two interfaces
which can be implemented using let's say two traits - let's sayinterface Foo {
public function foo(): string;
}
trait HasFoo {
public function foo(): string { return 'foo'; }
}
interface Bar {
public function bar(): bool;
}
traitHasBar {
public function bar(): bool { return true; }
}Now I can need to implement Foo or Bar separately or together.
Using abstract class that would require 3 abstract classes: Foo, Bar, and FooWithBar.
With this RFC that would require just two interfaces with default methods.
This seems like a software design issue, not a language issue...
But 3 abstract classes vs. 2 interfaces + 2 traits seems like a better
tradeoff if you're going to need the coupling anyway. It's more
obvious that you want/require FooWithBar when you want it. If you're
expecting these exact implementations, moving them to the interface
makes it even more confusing.
I want FooWithBar (iow, I want these exact implementations)
I want Foo&Bar (iow, I don't care about the implementation)
You can pass a FooWithBar to Foo&Bar, but you can't pass a Foo&Bar to
a FooWithBar.
If the default implementation is on the interface ... who knows what
you have, you'll have to check you /vendor folder.
Not exactly, How you wanna solve by abstract class two interfaces
which can be implemented using let's say two traits - let's sayinterface Foo {
public function foo(): string;
}
trait HasFoo {
public function foo(): string { return 'foo'; }
}
interface Bar {
public function bar(): bool;
}
traitHasBar {
public function bar(): bool { return true; }
}Now I can need to implement Foo or Bar separately or together.
Using abstract class that would require 3 abstract classes: Foo, Bar, and FooWithBar.
With this RFC that would require just two interfaces with default methods.This seems like a software design issue, not a language issue...
But 3 abstract classes vs. 2 interfaces + 2 traits seems like a better
tradeoff if you're going to need the coupling anyway. It's more
obvious that you want/require FooWithBar when you want it. If you're
expecting these exact implementations, moving them to the interface
makes it even more confusing.I want FooWithBar (iow, I want these exact implementations)
I want Foo&Bar (iow, I don't care about the implementation)
You can pass a FooWithBar to Foo&Bar, but you can't pass a Foo&Bar to
a FooWithBar.If the default implementation is on the interface ... who knows what
you have, you'll have to check you /vendor folder.
You have to check your vendor folder for an interface, or trait, or abstract class. That doesn't change anything.
As noted, now consider a Baz interface. For interface-and-trait, you add 2 more definitions. For interface-with-defaults, you add 1. For abstract classes, you need to add 4: BazBase, FooBazBase, BarBazBase, and FooBarBazBase.
And that's assuming you're even in control of the base classes; you may not even be able to create all those combinations without lots of copy-pasta.
Abstract classes are basically vestigial since PHP 5.4, and have no use cases:
https://www.garfieldtech.com/blog/beyond-abstract
--Larry Garfield
You have to check your vendor folder for an interface, or trait, or abstract class. That doesn't change anything.
As noted, now consider a Baz interface. For interface-and-trait, you add 2 more definitions. For interface-with-defaults, you add 1. For abstract classes, you need to add 4: BazBase, FooBazBase, BarBazBase, and FooBarBazBase.
I guess I don't understand what the interface is solving if you're
creating an interface and a trait, why not just create the trait? It
sounds like you're coupling your interface to a specific
implementation and trying to get multi-inheritance out of PHP. This
seems like a design issue, and this RFC seems like a back-way to
multiple inheritance. Why not just allow multiple inheritance?
And that's assuming you're even in control of the base classes; you may not even be able to create all those combinations without lots of copy-pasta.
Abstract classes are basically vestigial since PHP 5.4, and have no use cases:
As a user of abstract classes since the early days of C++, I disagree.
I'd love to see a concrete example, but to me, this just seems like a
bandaid on an architectural smell.
Le 11/07/2023 à 17:16, Robert Landers a écrit :
You have to check your vendor folder for an interface, or trait, or abstract class. That doesn't change anything.
As noted, now consider a Baz interface. For interface-and-trait, you add 2 more definitions. For interface-with-defaults, you add 1. For abstract classes, you need to add 4: BazBase, FooBazBase, BarBazBase, and FooBarBazBase.
I guess I don't understand what the interface is solving if you're
creating an interface and a trait, why not just create the trait? It
What's solved here is that you simply don't have to create the trait
anymore, in this specific use case, no more, no less. And I do like it.
You may not see the point for it, but as a recurrent user of the
interface+trait from another package, it does bothers me a lot because
it's never clear about the intent when you don't know the trait exists.
Having the interface default methods makes it self-documenting and much
clearer for the user.
There's nothing complex here, it's pure sugar candy, and much
appreciated one by many I guess.
sounds like you're coupling your interface to a specific
implementation and trying to get multi-inheritance out of PHP. This
seems like a design issue, and this RFC seems like a back-way to
multiple inheritance. Why not just allow multiple inheritance?
Regarding the "back-way to multiple inheritance", it's true, and that's
how lots of languages that were not design with multiple inheritance in
mind solves it, such as Java, and I personally find this rather elegant.
--
Pierre
You have to check your vendor folder for an interface, or trait, or abstract class. That doesn't change anything.
As noted, now consider a Baz interface. For interface-and-trait, you add 2 more definitions. For interface-with-defaults, you add 1. For abstract classes, you need to add 4: BazBase, FooBazBase, BarBazBase, and FooBarBazBase.
I guess I don't understand what the interface is solving if you're
creating an interface and a trait, why not just create the trait? It
sounds like you're coupling your interface to a specific
implementation and trying to get multi-inheritance out of PHP. This
seems like a design issue, and this RFC seems like a back-way to
multiple inheritance. Why not just allow multiple inheritance?And that's assuming you're even in control of the base classes; you may not even be able to create all those combinations without lots of copy-pasta.
Abstract classes are basically vestigial since PHP 5.4, and have no use cases:
As a user of abstract classes since the early days of C++, I disagree.
I'd love to see a concrete example, but to me, this just seems like a
bandaid on an architectural smell.
Real code I wrote a week ago (specifically, for a series of events in a domain model):
https://gist.github.com/Crell/f5929e2ee44decd4e9353c41874f26c8
Two different interfaces, that I want to be able to check against, but their implementations are trivial. One of them is used in 2 classes, the other in 3. A base class simply wouldn't work, both because it's semantically incorrect (these events are not all "special cases of" some common definition, that's not the data model), and because then I couldn't have the class that uses only one of them. Traits, for now, are the best solution, and this is an approach that gets taken a lot.
Interface default methods saves a file, and lets us merge the traits into the interfaces. That's basically it. And that's helpful.
As for it being "back door multi-inheritance", well, Java, Kotlin, and Rust all do essentially that now. So we're hardly breaking new ground, design-wise. If anything, it's playing catch up on data modeling capabilities, an area where PHP is still sadly very much lacking.
--Larry Garfield
Real code I wrote a week ago (specifically, for a series of events in a domain model):
https://gist.github.com/Crell/f5929e2ee44decd4e9353c41874f26c8
Two different interfaces, that I want to be able to check against, but their implementations are trivial. One of them is used in 2 classes, the other in 3. A base class simply wouldn't work, both because it's semantically incorrect (these events are not all "special cases of" some common definition, that's not the data model), and because then I couldn't have the class that uses only one of them. Traits, for now, are the best solution, and this is an approach that gets taken a lot.
Ah, I see. I would have simply created an ErrorResponseCarrier class,
then had PreRouting and PostRouting extend them and implement whatever
other interfaces they needed.
IMHO, using a shared base class reflects the inheritance better
because they are siblings (at least these appear to be logical
siblings out of context, IMHO) and should look like siblings in a
class diagram. Their current dis-jointed-ness strikes me as odd and
the usage of traits in this way strikes me as an anti-pattern. But I
came from a PHP world where traits were nearly forbidden or used very
sparingly.
As for it being "back door multi-inheritance", well, Java, Kotlin, and Rust all do essentially that now. So we're hardly breaking new ground, design-wise. If anything, it's playing catch up on data modeling capabilities, an area where PHP is still sadly very much lacking.
There's a reason I don't use those languages :p but in all
seriousness, I get what you're saying.
Real code I wrote a week ago (specifically, for a series of events in a domain model):
https://gist.github.com/Crell/f5929e2ee44decd4e9353c41874f26c8
Two different interfaces, that I want to be able to check against, but their implementations are trivial. One of them is used in 2 classes, the other in 3. A base class simply wouldn't work, both because it's semantically incorrect (these events are not all "special cases of" some common definition, that's not the data model), and because then I couldn't have the class that uses only one of them. Traits, for now, are the best solution, and this is an approach that gets taken a lot.
Ah, I see. I would have simply created an ErrorResponseCarrier class,
then had PreRouting and PostRouting extend them and implement whatever
other interfaces they needed.IMHO, using a shared base class reflects the inheritance better
because they are siblings (at least these appear to be logical
siblings out of context, IMHO) and should look like siblings in a
class diagram. Their current dis-jointed-ness strikes me as odd and
the usage of traits in this way strikes me as an anti-pattern. But I
came from a PHP world where traits were nearly forbidden or used very
sparingly.
Traits are a surgical tool with a narrow set of uses, and systems that over-use them cause problems. (You know which framework you are...) But this is one of their main valid uses.
In context, the classes are not siblings, and it would be incorrect for them to extent from a base class. They just both happen to implement the same interface, but that the same as having the same "is a special case of" relationship with a base class.
Having a common base class instead would, as noted before, mean as soon as I added a third "carries" option, I'd have to add four more base classes to cover all combinations. It quickly gets absurd, and those base classes have no valid type usage; they're purely there as an alternative to copy-paste.
Using inheritance as an alternative to copy-paste is the wrong way(tm) to do it. Both inheritance and copy-paste. Freshman CS classes still love to talk about inheritance as a great thing for code reuse but... it's really not, and many of the 21st century languages have been drifting away from that.
Traits/default-method-interfaces are a better alternative that doesn't conflate "copy-paste avoidance" with "is a special case of." Honestly, I almost never use class inheritance in my greenfield code these days.
--Larry Garfield
IMHO, using a shared base class reflects the inheritance better
because they are siblings (at least these appear to be logical
siblings out of context, IMHO) and should look like siblings in a
class diagram. Their current dis-jointed-ness strikes me as odd and
the usage of traits in this way strikes me as an anti-pattern. But I
came from a PHP world where traits were nearly forbidden or used very
sparingly.Traits are a surgical tool with a narrow set of uses, and systems that over-use them cause problems. (You know which framework you are...) But this is one of their main valid uses.
In context, the classes are not siblings, and it would be incorrect for them to extent from a base class. They just both happen to implement the same interface, but that the same as having the same "is a special case of" relationship with a base class.
Having a common base class instead would, as noted before, mean as soon as I added a third "carries" option, I'd have to add four more base classes to cover all combinations. It quickly gets absurd, and those base classes have no valid type usage; they're purely there as an alternative to copy-paste.
Using inheritance as an alternative to copy-paste is the wrong way(tm) to do it. Both inheritance and copy-paste. Freshman CS classes still love to talk about inheritance as a great thing for code reuse but... it's really not, and many of the 21st century languages have been drifting away from that.
Traits/default-method-interfaces are a better alternative that doesn't conflate "copy-paste avoidance" with "is a special case of." Honestly, I almost never use class inheritance in my greenfield code these days.
I'm stating my +1 for this feature (though I can't vote since I lack vote karma), and also want to point that this is a feature in Swift as well, and used extensively through its standard library. (The actual mechanics are somewhat different, and significantly more powerful, both for good and ill. I'm handwaving a bit to not get bogged down in details that don't/can't matter for PHP.)
A basic example in Swift's standard library is the Equatable and Comparable interfaces. Both have partial implementations provided. Between the two, if you implement the == and < operations, the stdlib provides !=, <=, >, and >= automatically, but you can override them if desired by providing an explicit implementation. This is used pretty much everywhere; most of the builtin types (like Int, Float, String, and Array, which otherwise have no relation to each other and definitely don't inherit from some base type) implement Equatable and Comparable.
Another example is the Sequence interface, which comes with a set of default implementations for standard sequence algorithms, such as map, first, min/max, contains, etc. This allows all types of sequences to have the functionality expected of a sequence without needing to redundantly implement basic operations (unless desired) or participate in inheritance.
This clear distinction between what a type is (its type and inheritance tree) and what a type can do (the interfaces it implements) is really important when you start piling on the interfaces. Swift's standard library comes with a laundry list of interfaces that provide partial or complete default implementations, and it's entirely reasonable to combine these together. Consider, for example, a type that implemented each of Sequence, Collection, Encodable, Decodable, Equatable, and Hashable (such as Array or Dictionary). Creating a sane inheritance tree for that would be difficult. (And that's before considering that an array or dictionary should itself be Encodable/Decodable/Equatable/Hashable if its elements (and keys) have those properties. In Swift, the implementation for Array and Dictionary is largely the details of managing data storage. Useful algorithms get automatically inherited from default implementations from their many interfaces without needing a common parent class for both arrays and dictionaries, which are both structs which can't have inheritance anyway.)
I'll also point out that (in both PHP and Swift) enums can't participate in inheritance, but can implement interfaces. If one wanted to provide a default implementation for an interface used an enum, an abstract class isn't an option at all.
Anecdotally, outside of framework-mandated inheritance, the vast majority of my types in Swift are structs, enums, and classes with no inheritance, and many have interfaces that have some default implementation provided. Most of my PHP classes that have inheritance would be better served with interfaces + default implementations; they use inheritance only because it is currently the least bad way to make them work. Inheritance doesn't really capture the relationship between them (which is that there is none, save for their shared interface).
-John
Chatter on the Interface Default Methods RFC has been quiet for
the past 6 days, and the feature freeze deadline is fast approaching
for PHP 8.3, so I'm moving this to vote. It'll be open for two weeks
as usual.Thanks to everyone who discussed weaknesses in the RFC during the
discussion phase.
The voting period is about half-way through. For your information,
it's currently sitting at 10 yes and 13 no votes. Thanks to everyone
who has voted so far.
Chatter on the Interface Default Methods RFC has been quiet for
the past 6 days, and the feature freeze deadline is fast approaching
for PHP 8.3, so I'm moving this to vote. It'll be open for two weeks
as usual.Thanks to everyone who discussed weaknesses in the RFC during the
discussion phase.The voting period is about half-way through. For your information,
it's currently sitting at 10 yes and 13 no votes. Thanks to everyone
who has voted so far.
I really liked this idea actually but I'm still not so sure about it,
what would be the "right" approach. Just one question though. With
this, also the protected methods would be possible to define in the
interface? And what about the properties? Properties would be part of
some other RFC?
On Tue, 11 Jul 2023 at 13:37, Levi Morrison morrison.levi@gmail.com
wrote:On Sun, Jul 2, 2023 at 6:11 PM Levi Morrison morrison.levi@gmail.com
wrote:Chatter on the Interface Default Methods RFC has been quiet for
the past 6 days, and the feature freeze deadline is fast approaching
for PHP 8.3, so I'm moving this to vote. It'll be open for two weeks
as usual.Thanks to everyone who discussed weaknesses in the RFC during the
discussion phase.The voting period is about half-way through. For your information,
it's currently sitting at 10 yes and 13 no votes. Thanks to everyone
who has voted so far.I really liked this idea actually but I'm still not so sure about it,
what would be the "right" approach. Just one question though. With
this, also the protected methods would be possible to define in the
interface? And what about the properties? Properties would be part of
some other RFC?
It doesn't say they can't be used, so I assume we'll be able to use traits
in interfaces as well.
I really liked this idea actually but I'm still not so sure about it,
what would be the "right" approach.
So, here's a crazy thought: why do inheritance, interfaces, and traits need to be separate at all?
At some level, they're all ways of composing a class with different restrictions, e.g. inheritance requires a single parent, interfaces must be abstract, traits don't interact with typing, etc. This RFC was an attempt to lift some (but not all) of these restrictions on interfaces; in that sense, it almost seems like too small of a step, and one which leaves the language in a confusing intermediate state.
So, here's a crazy thought: why do inheritance, interfaces, and traits
need to be separate at all?At some level, they're all ways of composing a class with different
restrictions, e.g. inheritance requires a single parent, interfaces must be
abstract, traits don't interact with typing, etc. This RFC was an attempt
to lift some (but not all) of these restrictions on interfaces; in that
sense, it almost seems like too small of a step, and one which leaves the
language in a confusing intermediate state.
I agree with this statement. Although I can't vote, I would be for this
feature. However, abstract classes would become orphans with the approval
and should be more clarification in the RFC what to do with them and the
whole inheritance design in the language, because this is significant
change.
Perhaps a little too late, but I was wondering whether folks that voted NO
would reconsider in case this was made a bit more opt-in.
There could be some bikesheding around syntax but essentially the idea
would be a new RFC targeting 8.4 with the following adjustment:
interface Foo {
public function bar() {
echo "hello";
}
}
class Out implements Foo {}
// RFC is ignored.
// Fatal error: Class Out contains 1 abstract method and must therefore be
declared abstract or implement the remaining methods (Foo::bar)
class In use Foo {}
// RFC takes effect.
class In extends Foo {}
// RFC takes effect but the class is no longer allowed to extend abstract
classes, only interfaces
class In with Foo {}
// RFC takes effect
class In as Foo {}
// RFC takes effect
==========
In the spirit of minimizing impact, the proposed syntaxes only use keywords
already present in the language as to not run the risk of causing more
issues (https://www.php.net/manual/en/reserved.keywords.php).
This idea occurred to me when someone pointed out that they don't want to
implement interfaces which might bring code into their class.
Does this adjustment makes things better, worse or the same?
Looks - sadly to me - like this isn't going to pass. I don't have vote
karma and if I did it wouldn't make a difference to the outcome, but it
would be really good for those of us who can't vote on the feature to hear
from some of the people who voted against it why they chose no. The
feedback from the discussion here seemed overall positive. It's one of
those things that's just a bit opaque to me, that quite often I see people
voting no on an RFC and we haven't heard from them in the relevant
internals threads, so we just never know why something was rejected or what
the author could have said or changed in the RFC to persuade them.
Looks - sadly to me - like this isn't going to pass. I don't have vote
karma and if I did it wouldn't make a difference to the outcome, but it
would be really good for those of us who can't vote on the feature to hear
from some of the people who voted against it why they chose no. The
feedback from the discussion here seemed overall positive. It's one of
those things that's just a bit opaque to me, that quite often I see people
voting no on an RFC and we haven't heard from them in the relevant
internals threads, so we just never know why something was rejected or what
the author could have said or changed in the RFC to persuade them.
I share some of the sentiment. Although I think we have quite a few people
without a vote here on this thread which might had been enough to approve
this feature if we all collectively had a vote.
Unfortunately the voting system is another broken problem without a fix and
it's a really sad outcome at the end.
This would had been one of the best PHP improvements since Construction
Property Promotion and Short Arrow Functions
Chatter on the Interface Default Methods RFC has been quiet for
the past 6 days, and the feature freeze deadline is fast approaching
for PHP 8.3, so I'm moving this to vote. It'll be open for two weeks
as usual.Thanks to everyone who discussed weaknesses in the RFC during the
discussion phase.
Although I like the idea, I think the main reason for the pushback is how
close this is being voted on before feature freeze when the RFC +
implementation was updated very recently before.
And personally I think, considering this, I would also delay implementing
this.
We have at least 2 other major RFCs that are being pushed back (Property
Hooks and Function autoloading) due to time constraints.
Maybe it's time for a more meta discussion about the absurdly long release
process PHP has of releasing many intermediate versions that seem to get no
testing from userland.
For everyone against this feature, I would urge you to understand the
distinction between "type classes" and Java-like "interfaces" (which is
effectively what PHP interfaces are).
A good article is the following one:
https://diogocastro.com/blog/2018/06/17/typeclasses-in-perspective/
I also find it baffling the lack of understanding around this feature.
Generic programming exists, and it operates on a level where a method can
have a "concrete" default representation and still represent the genericity
to its fullest.
Examples have already been given, such as the Comparable, Equatable, or
Iterator type classes.
Considering, Haskell, Rust, Scala, and modern PL theory sees no issue with
that, I struggle to understand the resistance here.
Moreover, saying this capability should not be added to PHP because we have
inferior tools X + Y + Z to achieve what this does is counterproductive
and, IMHO, shows a clear lack of understanding of the issues PHP's model
currently has.
Traits are, and have always been, terribly designed. Assisted copy-paste
that has no relation to the type the implementation it provides fulfils.
Abstract classes allowing default implementations, but enforcing hierarchy
thus type relations, meaning they are unsuitable for when one wants
genericity (for separating concerns).
Interfaces which allow the creation of new types, but no generic
implementation which depend on a function specified by said interface.
Objectively, the current situation is suboptimal.
Maybe the resistance to the proposal would be far less if the RFC, and
implementation, would check at compile time that the default
implementations only rely on known existing functions available to the
interface.
Or that at least one of the methods would remain "abstract".
However, that does not seem what the discourse is.
I find the Rust Seek trait(/type class) a very concise example of the
usefulness, and where the implementation of a default method is far from
concrete.
Requiring an implementation to provide the implementation for seek(int
$position)
But being able to provide the trivial implementation of rewind()
which is
seek(0);
Sincerely,
George P. Banyard
Maybe the resistance to the proposal would be far less if the RFC, and
implementation, would check at compile time that the default
implementations only rely on known existing functions available to the
interface.
I asked in the discussion if this was a possibility, and it's the biggest
concern I had about the feature as proposed. Rowan answered "As the RFC
says, it introduces a form of multiple inheritance, and inheritance in PHP
doesn't make any such guarantee" and Levi added "I hope static analysis can
fill the gap here, but don't think these checks are necessary to ship this
feature" - and this is fair enough, I think; we kind of do accept the
nature of PHP is that there is some anti-intuitive weirdness versus
statically compiled languages. I wasn't convinced at first but I've come to
be persuaded even if it's not a perfect implementation of default methods
as I would have wanted them, it's still a significant improvement on the
trait + interface model we have now. It's ultimately a step in the right
direction and I'm disappointed now it looks like it's not going to happen,
at least in the next release. Would be good to know from some of the no
votes if they'd reconsider for a future version.
Chatter on the Interface Default Methods RFC has been quiet for
the past 6 days, and the feature freeze deadline is fast approaching
for PHP 8.3, so I'm moving this to vote. It'll be open for two weeks
as usual.Thanks to everyone who discussed weaknesses in the RFC during the
discussion phase.Although I like the idea, I think the main reason for the pushback is how
close this is being voted on before feature freeze when the RFC +
implementation was updated very recently before.
And personally I think, considering this, I would also delay implementing
this.
We have at least 2 other major RFCs that are being pushed back (Property
Hooks and Function autoloading) due to time constraints.Maybe it's time for a more meta discussion about the absurdly long release
process PHP has of releasing many intermediate versions that seem to get no
testing from userland.For everyone against this feature, I would urge you to understand the
distinction between "type classes" and Java-like "interfaces" (which is
effectively what PHP interfaces are).
A good article is the following one:
https://diogocastro.com/blog/2018/06/17/typeclasses-in-perspective/I also find it baffling the lack of understanding around this feature.
Generic programming exists, and it operates on a level where a method can
have a "concrete" default representation and still represent the genericity
to its fullest.
Examples have already been given, such as the Comparable, Equatable, or
Iterator type classes.
Considering, Haskell, Rust, Scala, and modern PL theory sees no issue with
that, I struggle to understand the resistance here.
If I could play armchair shrink for a moment, I suspect a lot of people come from a background where "interface is just the behavior definition, not implementation" was drilled into them. Which... is the case in older Java when most of us went through school using older Java. So it's natural to think that is just a rule of how languages work, and so default methods in interfaces is just some weird nonsense from people who don't understand language theory because you didn't learn it in school.
At least, I know that description applies to me, so I'm assuming it applies to at least some other folks around here. :-)
Realizing "oh, wait, I was wrong about the theory of how things work" is uncomfortable, and hard for a lot of people. I was initially luke-warm on it for that reason. But seeing how many languages have adopted some form of default methods and lived to tell the tale is convincing for me that it actually is a viable "build up a class from separate pieces without having to manually write 50 proxy methods" solution. There may be smaller issues with it that need to be ironed out (enforcing methods being defined, it working better with interface properties, etc.), but the core idea seems to be sound.
It's taken me a while to get used to going through that "oh wait, I was wrong" process, so at this point it's not an ego-hit. But that's not a process everyone has gone through.
In short, I suspect at least much of the pushback is "that is weird and not normal, according to the normal I first learned, so it must be a bad idea," and people just stop there.
(If you voted no and the above description doesn't apply to you, please do explain what your alternate reasoning is, because RFC authors desperately need more feedback than we get right now.)
--Larry Garfield
I want to pitch in, agreeing with Larry's message here.
- There are multiple real life use cases where the combo trait/interface could be replaced by interface default methods
- Several modern language apply the technique in one form or another, so it's already proven to be valuable
- There are a multitude of userland devs who'd benefit from this feature
- The only argument I've heard against this RFC is "it goes against my definition of what an interface should be". I was also thought that same definition, and I also had to unlearn it. Just like I had to unlearn the "only one return per method rule" we were taught in college
Brent
Chatter on the Interface Default Methods RFC has been quiet for
the past 6 days, and the feature freeze deadline is fast approaching
for PHP 8.3, so I'm moving this to vote. It'll be open for two weeks
as usual.Thanks to everyone who discussed weaknesses in the RFC during the
discussion phase.Although I like the idea, I think the main reason for the pushback is how
close this is being voted on before feature freeze when the RFC +
implementation was updated very recently before.
And personally I think, considering this, I would also delay implementing
this.
We have at least 2 other major RFCs that are being pushed back (Property
Hooks and Function autoloading) due to time constraints.Maybe it's time for a more meta discussion about the absurdly long release
process PHP has of releasing many intermediate versions that seem to get no
testing from userland.For everyone against this feature, I would urge you to understand the
distinction between "type classes" and Java-like "interfaces" (which is
effectively what PHP interfaces are).
A good article is the following one:
https://diogocastro.com/blog/2018/06/17/typeclasses-in-perspective/I also find it baffling the lack of understanding around this feature.
Generic programming exists, and it operates on a level where a method can
have a "concrete" default representation and still represent the genericity
to its fullest.
Examples have already been given, such as the Comparable, Equatable, or
Iterator type classes.
Considering, Haskell, Rust, Scala, and modern PL theory sees no issue with
that, I struggle to understand the resistance here.If I could play armchair shrink for a moment, I suspect a lot of people come from a background where "interface is just the behavior definition, not implementation" was drilled into them. Which... is the case in older Java when most of us went through school using older Java. So it's natural to think that is just a rule of how languages work, and so default methods in interfaces is just some weird nonsense from people who don't understand language theory because you didn't learn it in school.
At least, I know that description applies to me, so I'm assuming it applies to at least some other folks around here. :-)
Realizing "oh, wait, I was wrong about the theory of how things work" is uncomfortable, and hard for a lot of people. I was initially luke-warm on it for that reason. But seeing how many languages have adopted some form of default methods and lived to tell the tale is convincing for me that it actually is a viable "build up a class from separate pieces without having to manually write 50 proxy methods" solution. There may be smaller issues with it that need to be ironed out (enforcing methods being defined, it working better with interface properties, etc.), but the core idea seems to be sound.
It's taken me a while to get used to going through that "oh wait, I was wrong" process, so at this point it's not an ego-hit. But that's not a process everyone has gone through.
In short, I suspect at least much of the pushback is "that is weird and not normal, according to the normal I first learned, so it must be a bad idea," and people just stop there.
(If you voted no and the above description doesn't apply to you, please do explain what your alternate reasoning is, because RFC authors desperately need more feedback than we get right now.)
--Larry Garfield
--
To unsubscribe, visit: https://www.php.net/unsub.php
On Thu, Jul 13, 2023 at 8:46 AM Brent Roose via internals <
internals@lists.php.net> wrote:
I want to pitch in, agreeing with Larry's message here.
- There are multiple real life use cases where the combo trait/interface
could be replaced by interface default methods- Several modern language apply the technique in one form or another, so
it's already proven to be valuable- There are a multitude of userland devs who'd benefit from this feature
- The only argument I've heard against this RFC is "it goes against my
definition of what an interface should be". I was also thought that same
definition, and I also had to unlearn it. Just like I had to unlearn the
"only one return per method rule" we were taught in collegeBrent
This was a valuable message for me. It helps me pinpoint my frustration
with this RFC.
- We have userland desire
- There's prior art in other languages
- It's already "doable" (Interface+Trait)
- It adds a ton of convenience.
- I have not seen any negative opinion about the implementation or impact
on the php-src source code.
What we're left with is either:
- Let's have this but not on PHP 8.3 due to time constraint
- Let's not have this
If it's a time constraint, it would be good to hear more from folks that
voted no so that it can light up hope.
If it's just because voters don't want to let us have this then it's really
just frustrating.
I want to pitch in, agreeing with Larry's message here.
- There are multiple real life use cases where the combo trait/interface
could be replaced by interface default methods- Several modern language apply the technique in one form or another, so
it's already proven to be valuable- There are a multitude of userland devs who'd benefit from this feature
- The only argument I've heard against this RFC is "it goes against my
definition of what an interface should be". I was also thought that same
definition, and I also had to unlearn it. Just like I had to unlearn the
"only one return per method rule" we were taught in collegeBrent
If it's a time constraint, it would be good to hear more from folks that
voted no so that it can light up hope.
If it's just because voters don't want to let us have this then it's
really
just frustrating.
Hey internals, I know that I'm not that active around here but I wanted to
give my 2 cents
I totally agree with this.
We already have other languages that use this in one way or another and
it's a valuable feature for all these languages.
This is something that would save a lot of "boilerplate" code and
workarounds using Interfaces+Traits in a lot of places.
Also, this would be an opt-in thing, if you don't want to use default
methods in the interfaces and keep them just acting as "plain interfaces"
it won't change anything for you.
I don't see why this is having such a hard time being approved.
There have been other RFCs before that would really help the language to
evolve and if this fails to be implemented into the language I think we
should really reconsider the whole RFC process.
I just want to say that between all of you, I get this feature now.
Maybe someone should open an RFC where your vote doesn't count unless
you provide feedback on the list. (ban drive-by votes)
We may not have the power to vote, but we can open RFCs.
I just want to say that between all of you, I get this feature now.
Maybe someone should open an RFC where your vote doesn't count unless
you provide feedback on the list. (ban drive-by votes)We may not have the power to vote, but we can open RFCs.
Since a few people commented something to the effect of "if we're going to do this, we should go all the way to multiple inheritance for realsies," I decided to dig into that a little further.
I surveyed 14 major languages: C,C++, Java, Kotlin, Swift, Rust, Go, C#, Haskell, TypeScript, PHP, Javascript, Python, and Ruby.
Of them:
C++ and Python support multiple inheritance via extends mechanisms.
Java, Kotlin, Swift, Rust, and C# support interface default methods.
Go is weird, because it doesn't have inheritance per se, but its type composition system is almost multiple inheritance if you squint. And because it has structural typing, you can provide a method that applies to type A, and if type B uses type A, the method will work on B, too. So... it kinda sorta does interface default methods if you squint, but it's kinda squishy where you draw the line.
Haskell has type classes, not interfaces. Type classes are not the same thing as interfaces or inheritance, but effectively allow for functionality equivalent to interfaces with default implementations. The syntax is quite different, but the basic concept is there.
Typescript has mixins, which are not quite multiple inheritance since they happen at runtime, as far as I can figure. So, maybe they count as multiple inheritance, ish?
Javascript has nothing, because it barely has a type system.
Ruby has "modules", which I think are roughly equivalent to traits.
Based on that, I would conclude:
- Multiple inheritance is not a fringe old feature that has been left to the dustbin. A majority of languages surveyed have multiple inheritance in some fashion!
- Of those that do, a majority of them implement it via interface default methods, or their approximate language equivalent.
So it seems, based on the data, that this RFC is multiple inheritance, done the industry standard way, and multiple inheritance done this way is pretty common to the point that by not having it, PHP is in the minority.
So if you want "multiple inheritance done right", that's what this RFC is already.
I hope that helps clarify the context.
--Larry Garfield
Hi
I find the Rust Seek trait(/type class) a very concise example of the
usefulness, and where the implementation of a default method is far from
concrete.
Requiring an implementation to provide the implementation for seek(int
$position)
But being able to provide the trivial implementation ofrewind()
which is
seek(0);
(I'm not a Rust expert, but I've shipped production software with it. So
the following might not be entirely accurate, in this case I'm happy to
be corrected)
I don't think it is useful to compare PHP or this proposed RFC to what
Rust does. My understanding is that Rust methods are effectively just
syntax sugar for a regular function call. Specifically they have an
explicit parameter for the $this
value (commonly called self
).
Furthermore "methods" in Rust are effectively namespaced using the
struct or trait name they are defined in, thus implementing multiple
traits with a large number of default-implemented methods with generic
names will not cause conflicts:
In PHP all the methods would reside in a flat namespace. From my
experience this can already be a problem when needing to implement more
than one interface at the same time and this is not likely to improve if
the number of methods in an interface would increase (e.g. the mentioned
Iterator trait).
The use-case of reducing the BC impact of extending an interface by
providing a default method would also risk accidental collisions with
methods that already happen to exist in a child class. Incidentally this
effectively matches one of the examples given in my #[\Override] RFC
(the 4th Laravel Eloquent example) -
https://wiki.php.net/rfc/marking_overriden_methods#examples - though to
be clear #[\Override] cannot (yet) protect against that, because "no
implicit override" was left as future scope.
See also: https://phpc.social/@heiglandreas/110649571908678102. This
effectively makes the main selling point of the RFC moot. I'm aware this
limitation is acknowledged in the "Backward Incompatible Changes"
section. I do not think this makes it less of a problem, though.
Best regards
Tim Düsterhus
Chatter on the Interface Default Methods RFC has been quiet for
the past 6 days, and the feature freeze deadline is fast approaching
for PHP 8.3, so I'm moving this to vote. It'll be open for two weeks
as usual.Thanks to everyone who discussed weaknesses in the RFC during the
discussion phase.
The voting has ended. The final vote count is 15 yes to 17 no, so this
RFC is not accepted. Thanks to those who participated in the
discussion and the voting.