Send a blank email to [email protected] to get a copy of this message
Hello internals,
The discussion about allowing never types as parameter types made me think about what problem it is
truly trying to solve,
which is using the same type as parameters and return values between multiple methods of a common
interface.
This is normally solved with generics, but as shown generics are hard TM [1] and a lot of the
complexity resides in allowing the generic type to be set at *use* site of the class with generic
parameters.
However, this does not apply to template/generic types on interfaces, as the bound type is
determined by the implementing class at compile time.
As such, a few weeks ago, I created a PoC [2] where one can declare a template/associated type T on
interfaces that require an implementing class uses the same type when specifying T.
The syntax in the PoC is currently:
```
interface I {
type T : int|string;
public function foo(T $param): T;
}
class CS implements I {
public function foo(string $param): string {
return $param . '!';
}
}
```
I.e. the associated type is indicated by a "type" keyword, optionally followed by a colon
: and a type constraint.
The type corresponding to the associated type is currently "guessed" by the first usage in
a concrete class.
Having talked with Arnaud off-list, it seems that using the "usual" generic syntax of
(assuming our parser can cope with it):
```
interface I<T : int|string> {
public function foo(T $param): T;
}
class CS implements I<string> {
public function foo(string $param): string {
return $param . '!';
}
}
```
is possible and would not conflict with any future proposal for generics.
Importantly, this feature would NOT support doing the followings:
- $o instanceof I<ConcreteType>
- Using I<ConcreteType> in type declarations
Meaning you do not get static type information, similarly to the never as parameter
type,
but one is guaranteed that there is no funky type variance and incompatibilities between different
methods (or parameter and return types of the same method) in a concrete implementation of an
interface.
Effectively, static analysis tools must either assume T is mixed, or hook it into their
generic types feature.
Which is what the current status is for various interfaces (e.g. ArrayAccess).
I am intending on getting this feature ready for 8.5, and the reason I bring it up to the list now,
without a proper RFC, is to explain my reasoning for why I am voting against the never parameter
type RFC. [3]
For any questions, feel free to reply, but please do remember that this is still a bit in flux.
Best regards,
Gina P. Banyard
[1] https://thephp.foundation/blog/2024/08/19/state-of-generics-and-collections/
[2] https://github.com/php/php-src/pull/18260
[3] https://wiki.php.net/rfc/never-parameters-v2