>
> But this leads to code that can't pass static inspections?
>

No.


> interface Joiner {
>     public function join(array $array): string;
> }
>
> class WideJoiner implements Joiner {
>     public function join($iterable): string {
>         $array = is_array($iterable) ? $array :
> iterable_to_array($iterable);
>
>         return implode(", ", $array);
>     }
> }
>
> function joinWith(Joiner $joiner, $iterable) {
>     return $joiner->join($iterable); // <-- invalid argument ?
> }
>

Yes, a static analysis engine should report invalid argument. If you depend
on another thing being accepted, you shouldn't declare just Joiner but
instead an extending interface or an implementation directly.


> According to the Joiner abstraction, only array is accepted, and that's
> all a static analysis tool can know about the $joiner argument in the
> joinWith() function.
>

Correct, that's why the static analysis engine should throw a warning on
that code.


> Being unable to pass static inspections is one thing, but this also makes
> the code generally difficult to explain
>

How so?


> there's a contract, Joiner, which states that an array is required - to a
> person reading the joinWith() function, that's all they can know about a
> Joiner instance
>

Correct.


> it isn't safe for anybody to depend on a specific implementation of Joiner
> with a widened argument-type
>

It is safe as long as you depend on the specific implementation or an
extended interface with the widened argument type.


> unless they read through the entire codebase and happen to know about the
> WideJoiner implementation, but even then, someone using the joinWith()
> function would also need to know which implementation of Joiner is being
> passed
>

You'd just declare that you depend on a Joiner that accepts also iterables.


> which seems to defeats the purpose of even having an abstraction in the
> first place?
>

So your argument is basically that contra-variance is never needed?

Regards, Niklas

Reply via email to