> > 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