# [VOTE] Interface Default Methods

- Thread: https://externals.io/message/120725
- Original archive: https://news-web.php.net/php.internals/120725
- Started by Levi Morrison on 2023-07-03T00:11:05+00:00
- Messages: 44
- RFC: Interface Default Methods (Declined) — https://externals.io/rfc/interface-default-methods.md
- Page 1 of 2: messages 1 to 25 (25 per page, add `?page=N` to the URL)
- Next page: https://externals.io/message/120725.md?page=2
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · RFCs at https://externals.io/rfc.md · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #120725 — Levi Morrison — 2023-07-03T00:11:05+00:00

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

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

---

## #120726 — Deleu — 2023-07-03T00:28:30+00:00

URL: https://externals.io/message/120725#120726 · In reply to: #120725

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
>
> --
> 
> To unsubscribe, visit: https://www.php.net/unsub.php
>
>
That's wonderful news Levi! Good luck to us all on this RFC!!

-- 
Marco Deleu

---

## #120727 — Ben Ramsey — 2023-07-03T01:08:40+00:00

URL: https://externals.io/message/120725#120727 · In reply to: #120725

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

---

## #120728 — Levi Morrison — 2023-07-03T02:43:27+00:00

URL: https://externals.io/message/120725#120728 · In reply to: #120727

>
> 
>
> ﻿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;
```

---

## #120729 — Ben Ramsey — 2023-07-03T03:01:19+00:00

URL: https://externals.io/message/120725#120729 · In reply to: #120728

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

---

## #120730 — Andreas Heigl — 2023-07-03T04:33:21+00:00

URL: https://externals.io/message/120725#120730 · In reply to: #120725

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

---

## #120731 — tim@bastelstu.be — 2023-07-03T08:54:07+00:00

URL: https://externals.io/message/120725#120731 · In reply to: #120725

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

---

## #120732 — michal.brzuchalski@gmail.com — 2023-07-03T11:32:33+00:00

URL: https://externals.io/message/120725#120732 · In reply to: #120725

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

---

## #120733 — michal.brzuchalski@gmail.com — 2023-07-03T11:39:50+00:00

URL: https://externals.io/message/120725#120733 · In reply to: #120730

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

---

## #120734 — Pierre — 2023-07-03T11:50:41+00:00

URL: https://externals.io/message/120725#120734 · In reply to: #120732

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

---

## #120735 — michal.brzuchalski@gmail.com — 2023-07-03T12:21:46+00:00

URL: https://externals.io/message/120725#120735 · In reply to: #120734

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

---

## #120736 — Andreas Heigl — 2023-07-03T12:25:57+00:00

URL: https://externals.io/message/120725#120736 · In reply to: #120732

Hey Michał


> Hi Levi,
> 
> pon., 3 lip 2023 o 02:11 Levi Morrison <morrison.levi@gmail.com> napisał(a):
> 
> > […]
> 
> 
> 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                          |
+---------------------------------------------------------------------+

---

## #120737 — michal.brzuchalski@gmail.com — 2023-07-03T12:45:18+00:00

URL: https://externals.io/message/120725#120737 · In reply to: #120736

pon., 3 lip 2023 o 14:26 Andreas Heigl <andreas@heigl.org> napisał(a):

> Hey Michał
>
> 
> > […]
> napisał(a):
> > […]
>
> I've added two already possible solutions to that as comments.
> > […]
>
> 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.
>
> > […]
>
> 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

---

## #120739 — Levi Morrison via internals — 2023-07-03T14:01:24+00:00

URL: https://externals.io/message/120725#120739 · In reply to: #120731

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

---

## #120741 — Deleu — 2023-07-03T15:31:44+00:00

URL: https://externals.io/message/120725#120741 · In reply to: #120736

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

---

## #120771 — Levi Morrison — 2023-07-11T11:37:03+00:00

URL: https://externals.io/message/120725#120771 · In reply to: #120725

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

---

## #120772 — Robert Landers — 2023-07-11T12:54:17+00:00

URL: https://externals.io/message/120725#120772 · In reply to: #120741

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

---

## #120773 — michal.brzuchalski@gmail.com — 2023-07-11T13:54:32+00:00

URL: https://externals.io/message/120725#120773 · In reply to: #120772

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

---

## #120774 — Deleu — 2023-07-11T14:02:12+00:00

URL: https://externals.io/message/120725#120774 · In reply to: #120773

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

---

## #120775 — Robert Landers — 2023-07-11T14:04:21+00:00

URL: https://externals.io/message/120725#120775 · In reply to: #120773

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

---

## #120776 — Larry Garfield — 2023-07-11T14:36:09+00:00

URL: https://externals.io/message/120725#120776 · In reply to: #120775

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

---

## #120777 — Robert Landers — 2023-07-11T15:16:11+00:00

URL: https://externals.io/message/120725#120777 · In reply to: #120776

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

---

## #120778 — Pierre — 2023-07-11T15:51:45+00:00

URL: https://externals.io/message/120725#120778 · In reply to: #120777

Le 11/07/2023 à 17:16, Robert Landers a écrit :
> 
> > […]
> 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

---

## #120779 — Larry Garfield — 2023-07-11T16:47:57+00:00

URL: https://externals.io/message/120725#120779 · In reply to: #120777

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

---

## #120780 — Robert Landers — 2023-07-11T17:28:06+00:00

URL: https://externals.io/message/120725#120780 · In reply to: #120779

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

---

Next page: https://externals.io/message/120725.md?page=2
