Re: Re: [RFC] [Discussion] Never parameters

From: Date: Tue, 15 Apr 2025 21:29:09 +0000
Subject: Re: Re: [RFC] [Discussion] Never parameters
References: 1 2 3  Groups: php.internals 
Request: Send a blank email to [email protected] to get a copy of this message
On Tue, 15 Apr 2025 at 20:59, Daniel Scherzer
<[email protected]> wrote:
>
> On Tue, Apr 8, 2025 at 6:40 PM Daniel Scherzer <[email protected]> wrote:
>>
>>
>> Since a lot of the discussion seems to be around static analysis and whether there is a
>> real use case for this, I wanted to share another use case I just came across: in the
>> thephpleague/commonmark package, different renderers are added to render different
>> types (subclasses) of League\CommonMark\Node\Node.
>
>
>
> I added this example to the RFC page as an example of how this could be useful in userland
> code. Barring further developments, I plan to open the RFC for voting in a few days.
>
> -Daniel
>

Thank you,
I have been wanting this since a long time!
https://externals.io/message/100275

----

One interesting application is intersection types.
https://externals.io/message/115712#123276
The intersection of different types with "never" parameters and
"mixed" return types naturally produces a valid new type:
(function(A, never): mixed) & (function(never, B): mixed) &
(function(never, never): R) === function (A, B): R
(imagine all of the above to be interfaces)

----

An interesting question I wonder is whether we would ever want
"constrained never" parameters.
E.g. currently we can have an interface I with function (A&B), where A
and B are classes/interfaces.
A sub-interface J that extends I can have function (A) or function (B)
or function (mixed) or function (A|SomethingElse).
But it cannot have function (C), if neither A nor B extends C.

In the same way, for function(int&string), a child method would have
to allow at least int or string, e.g. it cannot be function(float) or
function(C).
(it could be extended as function(int|float) or function(mixed), but
not function(float).)
So in a way this could be a more suitable parameter type for
BackedEnum::from() and ::tryFrom().

For the main part of this RFC we do not need to worry about this.
For the BackedEnum::from() and ::tryFrom(), if we change the type to
'never' now, we can no longer change it to int&string later without
breaking BC.

----

Another thing I wonder is whether the "Proposal" section needs to more
explicitly define the behavior.
Can we rely on the "Introduction" part and the examples in other
sections, or does the "Proposal" part need to be complete and
sufficient by itself?

What would we add, and what would be redundant?

"A method with a never parameter cannot be called."
This already follows from "it cannot be used in the declaration of any
method that has an implementation.", so we do not need to explicitly
add it.

"The never parameter type can only be used standalone, not as part of
a union or intersection or nullable type".
This might already be specified elsewhere, where never is defined as a
return type.

"A child class or interface that overrides a method with a never
parameter can replace the never parameter type with any other type, or
omit the parameter type altogether."
This is obvious to us from LSP, but do we need to explicitly define it?
It is currently mentioned in "Introduction" but not in "Proposal".

"A child class or interface that overrides a method with a never
parameter must respect LSP for the other parameters."
So, you cannot extend a function(A, never) with function(never, never).
I think this is pretty clear from general rules about covariance/contravariance.

So the only point that might make sense to add is the third one about
widening the type.

-- Andreas


Thread (33 messages)

« previous php.internals (#127117) next »