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