[VOTE] Interface Default Methods

php.internals

Levi Morrison

3 years ago
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. Thanks to everyone who discussed weaknesses in the RFC during the discussion phase. [1]: https://wiki.php.net/rfc/interface-default-methods

Deleu

3 years ago
On Sun, Jul 2, 2023 at 9:11 PM Levi Morrison <morrison.levi@gmail.com> wrote:
> 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. > > Thanks to everyone who discussed weaknesses in the RFC during the > discussion phase. > > [1]: https://wiki.php.net/rfc/interface-default-methods > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: https://www.php.net/unsub.php > >
That's wonderful news Levi! Good luck to us all on this RFC!!
-- Marco Deleu

Ben Ramsey

3 years ago
> On Jul 2, 2023, at 19:11, Levi Morrison <morrison.levi@gmail.com> wrote: > > 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. > > Thanks to everyone who discussed weaknesses in the RFC during the > discussion phase. > > [1]: https://wiki.php.net/rfc/interface-default-methods
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 [1]: https://externals.io/message/120213#120723

Levi Morrison

3 years ago
On Sun, Jul 2, 2023 at 7:08 PM Ben Ramsey <ben@benramsey.com> wrote:
> > On Jul 2, 2023, at 19:11, Levi Morrison <morrison.levi@gmail.com> wrote: > > 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. > > Thanks to everyone who discussed weaknesses in the RFC during the > discussion phase. > > [1]: https://wiki.php.net/rfc/interface-default-methods > > > > 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 <?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; ```

Ben Ramsey

3 years ago
> On Jul 2, 2023, at 21:43, Levi Morrison <morrison.levi@gmail.com> wrote: > > On Sun, Jul 2, 2023 at 7:08 PM Ben Ramsey <ben@benramsey.com> wrote: >> >> 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: >
Thanks for the response. This makes perfect sense to me now. Cheers, Ben

Andreas Heigl

3 years ago
Am 03.07.23 um 02:11 schrieb Levi Morrison:
> 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. > > Thanks to everyone who discussed weaknesses in the RFC during the > discussion phase. > > [1]: https://wiki.php.net/rfc/interface-default-methods >
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 | +---------------------------------------------------------------------+

Michał Brzuchalski

3 years ago
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][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. > > > > Thanks to everyone who discussed weaknesses in the RFC during the > > discussion phase. > > > > [1]: https://wiki.php.net/rfc/interface-default-methods > > > 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

Tim Düsterhus

3 years ago
Hi On 7/3/23 02:11, Levi Morrison wrote:
> 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

Unnamed Person

3 years ago
On Mon, Jul 3, 2023 at 2:54 AM Tim Düsterhus <tim@bastelstu.be> wrote:
> > Hi > > On 7/3/23 02:11, Levi Morrison wrote: > > 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 > > -- > PHP Internals - PHP Runtime Development Mailing List > 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.

Michał Brzuchalski

3 years ago
Hi Levi, pon., 3 lip 2023 o 02:11 Levi Morrison <morrison.levi@gmail.com> napisał(a):
> 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. > > Thanks to everyone who discussed weaknesses in the RFC during the > discussion phase. > > [1]: https://wiki.php.net/rfc/interface-default-methods
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

Pierre

3 years ago
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

Michał Brzuchalski

3 years ago
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 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. >
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

Andreas Heigl

3 years ago
Hey Michał On 03.07.23 13:32, Michał Marcin Brzuchalski wrote:
> Hi Levi, > > pon., 3 lip 2023 o 02:11 Levi Morrison <morrison.levi@gmail.com> napisał(a): > >> 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. >> >> Thanks to everyone who discussed weaknesses in the RFC during the >> discussion phase. >> >> [1]: https://wiki.php.net/rfc/interface-default-methods > > > 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 | +---------------------------------------------------------------------+

Michał Brzuchalski

3 years ago
pon., 3 lip 2023 o 14:26 Andreas Heigl <andreas@heigl.org> napisał(a):
> Hey Michał > > On 03.07.23 13:32, Michał Marcin Brzuchalski wrote: > > Hi Levi, > > > > pon., 3 lip 2023 o 02:11 Levi Morrison <morrison.levi@gmail.com> > napisał(a): > > > >> 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. > >> > >> Thanks to everyone who discussed weaknesses in the RFC during the > >> discussion phase. > >> > >> [1]: https://wiki.php.net/rfc/interface-default-methods > > > > > > 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`. >
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

Deleu

3 years ago
> > Stop using `implements` at all and solely rely on `use`. > > 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

Robert Landers

3 years ago
> > 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.

Michał Brzuchalski

3 years ago
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

Deleu

3 years ago
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 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 > >
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

Robert Landers

3 years ago
> 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.
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.

Larry Garfield

3 years ago
On Tue, Jul 11, 2023, at 2:04 PM, Robert Landers wrote:
>> 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. > > 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

Robert Landers

3 years ago
On Tue, Jul 11, 2023 at 4:36 PM Larry Garfield <larry@garfieldtech.com> wrote:
> 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.

Pierre

3 years ago
Le 11/07/2023 à 17:16, Robert Landers a écrit :
> On Tue, Jul 11, 2023 at 4:36 PM Larry Garfield <larry@garfieldtech.com> wrote: >> 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

Larry Garfield

3 years ago
On Tue, Jul 11, 2023, at 3:16 PM, Robert Landers wrote:
> On Tue, Jul 11, 2023 at 4:36 PM Larry Garfield <larry@garfieldtech.com> wrote: >> 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

Levi Morrison

3 years ago
On Sun, Jul 2, 2023 at 6:11 PM Levi Morrison <morrison.levi@gmail.com> wrote:
> > 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. > > Thanks to everyone who discussed weaknesses in the RFC during the > discussion phase. > > [1]: https://wiki.php.net/rfc/interface-default-methods
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.

Peter Kokot

3 years ago
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][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. > > > > Thanks to everyone who discussed weaknesses in the RFC during the > > discussion phase. > > > > [1]: https://wiki.php.net/rfc/interface-default-methods > > 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?

Robert Landers

3 years ago
On Tue, Jul 11, 2023 at 9:04 PM Peter Kokot <petk@php.net> wrote:
> 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][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. > > > > > > Thanks to everyone who discussed weaknesses in the RFC during the > > > discussion phase. > > > > > > [1]: https://wiki.php.net/rfc/interface-default-methods > > > > 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.

Dusk

3 years ago
On Jul 11, 2023, at 12:03, Peter Kokot <petk@php.net> wrote:
> 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.

Joerg Sowa

3 years ago
> 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.

Deleu

3 years ago
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?

David Gebler

3 years ago
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.

Deleu

3 years ago
On Tue, Jul 11, 2023, 7:32 PM David Gebler <davidgebler@gmail.com> wrote:
> 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

Girgias

3 years ago
On Mon, 3 Jul 2023 at 01:11, Levi Morrison <morrison.levi@gmail.com> wrote:
> 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. > > Thanks to everyone who discussed weaknesses in the RFC during the > discussion phase. > > [1]: https://wiki.php.net/rfc/interface-default-methods >
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

David Gebler

3 years ago
On Wed, Jul 12, 2023 at 5:01 AM G. P. B. <george.banyard@gmail.com> wrote:
> > 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.

Larry Garfield

3 years ago
On Wed, Jul 12, 2023, at 4:00 AM, G. P. B. wrote:
> On Mon, 3 Jul 2023 at 01:11, Levi Morrison <morrison.levi@gmail.com> wrote: > >> 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. >> >> Thanks to everyone who discussed weaknesses in the RFC during the >> discussion phase. >> >> [1]: https://wiki.php.net/rfc/interface-default-methods >> > > 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

Unnamed Person

3 years ago
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

Deleu

3 years ago
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 college > > Brent >
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.

Wendell Adriel

3 years ago
>> 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 >>
> 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.

Robert Landers

3 years ago
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.

Larry Garfield

3 years ago
On Thu, Jul 13, 2023, at 3:09 PM, Robert Landers wrote:
> 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

Tim Düsterhus

3 years ago
Hi On 7/12/23 06:00, G. P. B. wrote:
> 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); >
(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: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=5fe33b54187f110a8794c90e3a608466 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

Unnamed Person

3 years ago
On Sun, Jul 2, 2023 at 6:11 PM Levi Morrison <morrison.levi@gmail.com> wrote:
> > 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. > > Thanks to everyone who discussed weaknesses in the RFC during the > discussion phase. > > [1]: https://wiki.php.net/rfc/interface-default-methods
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.