On Fri, Mar 28, 2025, at 3:42 PM, Matt Fonda wrote:
> Hi Tim and Larry,
>
> Thanks for sharing examples. I'm not sure I follow how never parameters 
> help in either of these cases. As far as I can tell, the problem 
> remains that these methods can't actually be called.

> I share Nikita's sentiment in the previous RFC discussion [1], and have 
> yet to see an answer to it:
>
>> I don't think this really addresses my concern, so let me repeat it: You
>> cannot actually call a method using a never-type argument while typing
>> against the interface. What's the point of the interface then?
>> 
>> I don't think "you must use this in conjunction with a 3rd-party phpdoc
>> generics implementation for it to make any sense at all" is a suitable way
>> to resolve that.
>
> On Fri, Mar 21, 2025 at 8:53 AM Larry Garfield <la...@garfieldtech.com> wrote:
>> Changing the interface to use `never` instead of `mixed` would have the 
>> weakest guarantees of the three, since it doesn't force me to use the *same* 
>> widened type on serializeInt(), serializeFloat(), serializeString(), etc., 
>> even though it would always be the same.  But it would allow me to 
>> communicate more type information than I can now.
>
> Suppose you made this change from mixed to never. As long as you're 
> typing against the Formatter interface and not a specific 
> implementation, then you cannot actually call 
> $formatter->serializeInt() etc. because the interface defines the 
> parameter type as never, and you cannot call a method with a parameter 
> type of never.
>
> This is the case in your real world usage [1]. Here, 
> $serializer->formatter is typed against Formatter [2], not a specific 
> implementation. As such, all we know is that we have an instance of 
> Formatter--we don't know anything about the concrete type--and thus we 
> can't actually call e.g. serializeInt() because never is the only type 
> we know here.

I have to think people are misunderstanding Nikita's earlier comment, or 
perhaps that he phrased it poorly.  

The determination of whether a method call is type-compatible with the 
parameters passed to it is made *at runtime*, on the class.  You can widen a 
parameter type in an implementing class, and it will work.  That's been the 
case since PHP 7.4.

For example: https://3v4l.org/5YPdg

Even though the function is typed against I, if it's passed a C, you can call 
it with a string.  That's because C::a()'s param type is wider than the 
interface.

The idea of a never typed parameter is exactly the same: It starts off 
super-narrow (accepts nothing), so implementations can accept anything wider 
than "nothing" and still be type compatible.  You *can* call it.

What you cannot do is determine *statically* that it is callable, because at 
static-analysis time, all you know is the interface.  So SA tools won't be able 
to verify that anything is valid for that interface.  That's a valid criticism 
of never params, I agree.  Is it enough to vote against it on those grounds?  
That's up to each voter to decide.

But "you cannot ever even call it" is simply not true, unless there's some 
weird engine limitation that I don't know about.

In fairness, though, it seems to me that Associated Types would have the same 
SA issue.  It would probably be more evident for them that they cannot try to 
enforce the type statically, but I don't know how they could do a better job of 
reporting it than with a never type.  (Someone else who understands Associated 
Types better than I, how would that work?)

--Larry Garfield

Reply via email to