On 21/03/2025 11:50, Tim Düsterhus wrote:
Am 2025-03-20 21:27, schrieb Matt Fonda:
If an interface adds a method but makes no promises about what parameters
it accepts, then why is it part of the interface in the first place--why
add a method that can't be used?It would more cleanly allow for userland / PHPDoc-based generics, while still providing some engine-enforced type safety. Consider this example (not sure if I got the syntax completely right):
/\*\* @template T \*/ interface Comparable \{ /\*\* @param T $other \*/ public function compareTo\(never $other\): int; \} /\*\* @implements Comparable<Number> \*/ final class Number implements Comparable \{ public function compareTo\(Number $other\): int \{ return $this <=> $other; \} \}
I think I agree with Matt on this: the interface isn't making any usable promises about that method.
In this example, Comparable is a kind of "abstract interface" - in order to actually make use of it, you need to specialise it.
Declaring that a class implements a template interface is like inheriting an abstract method: either you fill in the type parameter ("class Foo implements Comparable<Foo> { ... }"), or the class is also a template ("class Foo<A> implements Comparable<A> { ... }")
I don't think the language should pretend to support something that it doesn't - if the contract is actually enforced by a third-party tool reading docblocks, put the contract in a docblock:
/\*\*
\* @template T
\* @method compareTo\(T $other\): int;
\*/
interface Comparable \{
\}
/\*\* @implements Comparable<Number> \*/
final class Number implements Comparable \{
public function compareTo\(Number $other\): int \{ return $this <=> $other; \}
\}
--
Rowan Tommins
[IMSoP]