Hi Brent,

wt., 27 sie 2024 o 09:28 Brent Roose <brent.ro...@jetbrains.com> napisał(a):

> Good morning internals
>
> I’d like to test the waters about an RFC idea: allowing traits to
> implement interfaces, and consequently a class that uses such a trait will
> automatically implement the interface as well.
>
> The original idea comes from Rust, where traits can be used as types. I
> read a very inspiring post suggested by Larry, on the topic of “classic
> inheritance” vs the way Rust and Go approach it [1]. The tl;dr is that both
> Rust and Go solve several pitfalls of classical inheritance (the diamond
> problem and inheritance abuse), thanks to a much simpler approach. In
> Rust’s case that is by using traits. If you have the time, I highly
> recommend reading that post, it’s super interesting and it gives a lot of
> good arguments for rethinking inheritance.
>
> Back to PHP, using traits as types seems impossible, since traits are a
> compile-time copy/paste mechanism, which means there’s no type information
> available about them at runtime.
>
> However, allowing traits to implement interfaces would solve this problem:
> these interfaces would be copied over to classes during compile-time, and
> the interface’s type information is available at runtime. On top of that,
> traits already have well-defined rules for conflict resolution, so we
> wouldn’t need any additional syntax to handle edge cases.
>
> Even though PHP traits differ from Rust, PHP developers already seem to
> like the idea of being able to “attach a type to a trait” one way or
> another. Let me name a couple of things that happen today:
>
>
>    -
>
>    Laravel often provides “default implementations” for their interfaces
>    via a trait [2]. As mentioned before, traits already deal with
>    conflict-resolution, so method collisions aren’t a blocker.
>    -
>
>    Both PHPStan and Psalm have an annotation that forces trait users to
>    implement an interface [3], which is essentially the feature I’m
>    describing, albeit via docblock annotations instead of proper syntax.
>    -
>
>    Even though it was not accepted, the interface default methods RFC
>    approached the problem from a different angle [4]. While a majority
>    disagreed that interfaces should implement their own methods directly, I
>    remember it was a heavily debated topic, and believe that approaching it
>    from the other side might be easier to accept.
>
>

With the recent RFC proposal for Default Expressions
<https://wiki.php.net/rfc/default_expression> [5], I believe it presents an
excellent opportunity to revisit the Interface Default Methods proposal.
The Default Expressions RFC addresses similar functionality and, when
combined with an opt-in feature flag, could resolve many concerns raised
during the previous discussion.

*Opt-In Feature Flag:* To address backward compatibility concerns, I
propose the introduction of a feature flag, such as declare(default_methods
= 1);, that could be applied when implementing an interface or when an
interface extends another. This approach would allow developers to opt-in
explicitly, preventing unintended BC breaks and ensuring that the feature
is adopted carefully and intentionally.

*Backward Compatibility Concerns:* The main concern from the previous
discussion was the risk of BC breaks when new methods are added to an
interface, potentially conflicting with existing implementations. Although
the original RFC suggested that default implementations could mitigate
these risks, contributors were worried that this might encourage developers
to introduce BC breaks without proper versioning. The opt-in flag would
make it clear when the feature is being used, thereby reducing the risk of
unintentional conflicts.

*Complexity and Developer Experience:* While the feature could
significantly improve the developer experience, it also introduces
complexity in how interfaces are used. To alleviate this, the default
keyword could be explicitly used to mark default methods, making it easier
for developers to understand and manage. For example:

interface I1 {
    default public function foo(): int {
        return \PHP_INT_MAX;
    }
}

This explicit marking not only clarifies the intention behind the method
but also aids in distinguishing between regular and default methods,
simplifying the mental model required to work with interfaces.

I believe these adjustments could make the Interface Default Methods more
palatable to the community, ensuring that the feature enhances PHP without
introducing unnecessary risks.

Just thinking out loud here - looking forward to hearing some thoughts.

Cheers,
Michał Marcin Brzuchalski

*Links:*
[4] Interface Default Methods RFC
<https://wiki.php.net/rfc/interface-default-methods>
[5] Default Expressions RFC <https://wiki.php.net/rfc/default_expression>

Reply via email to