On Sat, Aug 14, 2021, 01:27 Jordan LeDoux <jordan.led...@gmail.com> 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.
>

Hey Jordan,

>From type perspective, this sounds good.

But, in my view, types should be checked statically.
For inheritance, when defining a method, both the parameters and return
types are nicely checked statically and that's good.
On the other side, when calling a method, due to the dynamic nature of PHP,
there is no simple way of checking it statically.

For example, if an interface is defining a method with a parameter of type
string and an implementation is changing the parameter type to a string|int
union, the caller that have a knowledge about the interface (that accepts
only string) can call it with an integer and everything will work fine.
It's kind of the same situation and this will too be flagged by the IDEs
and static analysis tools.
>From a usage design perspective, this is bad, in my view. If caller knows
about the interface only, that is to ensure decoupling and this breaks it.

I was hoping that, at some point, we would be able to validate that
arguments types match parameters types statically, to avoid the continuous
runtime cost for it.
Maybe this can already be done, with some changes, when arguments are
properties defined with types.
When variables will have types and/or when variables will be
"final"/"constants", more static checks could be implemented.

Adding another exception to this behavior might not be the best idea if we
might move towards removing the behavior.

Coming back to the interface decoupling topic, that's exactly why
interfaces should be used, to allow polymorphism.
If I see an interface that was created just so it can be implemented by
multiple classes but the caller doesn't use the interface but it uses the
actual classes, I call it out as that is the wrong abstraction and the
interface should just be removed.

Your example with ArrayAccess is similar with this; when using it, you know
exactly what implementation you have. The interface is not helping here
related to polymorphism but it is actually required to allow a language
construct related to the engine itself, to translate accessing an object
with the same syntax as for an array.
If the 4 functions would have been magic methods, without an interface, you
would not have this problem.

Your example with CollectionInterface is exactly a place where I would say
the interface is unnecessary because you already know the implementation,
since you call it with the correct type. Just keeping the classes not
having to implement the interface would work just fine.

If you want to enforce method names on all Collection classes, you can do
that with other tools for static analysis, including code reviews; not with
the Interface.

Sorry for the long reply but my means to make it shorted are limited and
I'm using a smartphone only in this period (being in vacation).

Alex

Reply via email to