Re: [RFC] Never For Argument Types

From: Date: Sat, 14 Aug 2021 13:25:36 +0000
Subject: Re: [RFC] Never For Argument Types
References: 1  Groups: php.internals 
Request: Send a blank email to [email protected] to get a copy of this message
On Sat, Aug 14, 2021 at 1:27 AM Jordan LeDoux <[email protected]>
wrote:

> Hey internals,
>
> I've been working on the draft for my operator overloading RFC, and in
> doing so I encountered a separate change that I would like to see.
>
> That is, the use of never as an argument type for interfaces. Since
> arguments in PHP are contravariant to preserve Liskov substitution, never
> as the bottom type should indicate that implementing classes can require
> any type combination they want. This is in fact consistent with type theory
> and set theory, and is how the bottom type is treated in several other
> languages.
>
> In this case, the bottom type would be used to indicate covariant parameter
> polymorphism while not conflicting with LSP.
>
> This would provide a sort of minimal form of generics to PHP without the
> issues that actual generics present from an implementation perspective. It
> would not, however, restrict or hinder any future RFC for generics.
>
> This is at the first draft stage, and I currently have the RFC on a github
> repo to allow for easy contribution and collaboration.
>
> Any feedback is greatly appreciated.
>
> https://github.com/JordanRL/never-argument-type
>

There's two sides to this coin: While using a never argument type allows
you to avoid the LSP problem, it also means that you cannot call the method
while typing against the interface. Let's take your CollectionInterface

interface CollectionInterface {
    public function add(never $input): self;
}

and actually try to make use of it:

function addMultiple(CollectionInterface $collection, mixed ...$inputs):
void {
    foreach ($inputs as $input) $collection->add($input);
}

A static analyzer should flag this CollectionInterface::add() call as
invalid, because mixed is passed to never. Effectively, this means that an
interface using never argument types cannot actually be used in anything
*but* inheritance -- so what is its purpose?

Compare this to generics. The interface changes to

interface CollectionInterface<T> {
    public function add(T $input): self;
}

and the use changes to

function addMultiple<T>(CollectionInterface<T> $collection, T ...$inputs):
void {
    foreach ($inputs as $input) $collection->add($input);
}

Now a T argument is passed to a T parameter, and everything is fine.

Regards,
Nikita


Thread (30 messages)

« previous php.internals (#115719) next »