On Aug 16 2021, at 1:21 pm, Nikita Popov <nikita....@gmail.com> wrote:
> On Sat, Aug 14, 2021 at 3:44 PM Jordan LeDoux <jordan.led...@gmail.com>
> wrote:
>
> >
> >
> > On Sat, Aug 14, 2021 at 6:25 AM Nikita Popov <nikita....@gmail.com> wrote:
> >
> >>
> >> function addMultiple(CollectionInterface $collection, mixed ...$inputs):
> >> void {
> >> foreach ($inputs as $input) $collection->add($input);
> >> }
> >>
> >> A static analyzer should flag this CollectionInterface::add() call as
> >> invalid, because mixed is passed to never. Effectively, this means that an
> >> interface using never argument types cannot actually be used in anything
> >> *but* inheritance -- so what is its purpose?
> >>
> >>
> > When used as a sort of... pseudo-generics replacement, you'd need to use
> > Docblocks to specify these, because **this feature is not generics** (which
> > you correctly pointed out). I probably should have made that MORE clear so
> > as to not confuse or trick anyone.
> >
> > If this RFC were passed, it could be sort of used like generics but it
> > would be a bit hacky to use it that way as your example illustrates. In the
> > absence of generics, this would probably be used as a stopgap in
> > combination with docblocks. That's the point I was trying to make. :)
> >
> > The main value I see from an inheritance perspective is using never to
> > disallow an omitted type. The inheriting class may specify *any* type, even
> > mixed, but it must do so explicitly.
> >
>
> 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.
>
> The only case where this is somewhat sensible is with interfaces
> controlling engine behavior, like the operator overloading interfaces
> Addable etc you clearly have in mind here. If you never actually type
> against them and only use them as a marker for the engine, then this works
> out fine. But this still leaves the interface useless from a typesystem
> perspective, it merely becomes an engine marker.
>
> We have a better way to specify markers for the engine: Magic methods. I
> think some people have a mistaken notion that engine-integrated interfaces
> are always better than magic methods. This is only the case if such
> interfaces are actually useful from a type system perspective. For example,
> Countable and Traversable are useful magic interfaces, because you can
> sensibly type against them. The recently introduced Stringable interface
> (for the magic method __toString) falls in the same category.
>
> Conversely, Serializable is actively harmful as a magic interface (apart
> from the other issues with it), because whether an class implements
> Serializable does not determine whether it is serializable -- all objects
> are a priori serializable, the Serializable interface just gives it custom
> serialization behavior. You'll note that the new __serialize/__unserialize
> methods are plain magic methods without an interface. With exception of a
> custom serializer implementation, user code should never be checking for
> Serializable.
>
> The operator overloading case is in between: The interface is not actively
> harmful, but they also aren't useful. Given the lack of generics, it's not
> really possible to write code against a "Multiplyable" interface that
> actually provides a useful guarantee. The interface does not distinguish
> whether "T * T" is valid, or only scalar multiplication "T * float" is
> supported. When working with operator overloads in PHP, I expect usage to
> type against a specific class implementing operator overloading, say Money,
> rather than typing against something like Addable&Multiplyable. The latter
> would accept both Money and Matrix, both of which have entirely different
> rules on the kinds of operands they accept, even if they are, in some
> sense, addable and multiplyable.
>
> Regards,
> Nikita
>

Hi,
I think you make a very good point here that it only helps as a marker in 
engine-integrated interfaces.
That alone will allow usage of "specific types" (in parameters) when 
implementing them.

Also, as per OP, the patch is really trivial and might also help in operator 
overloading (in future).
> The operator overloading case is in between: The interface is not actively
> harmful, but they also aren't useful.
>

I think they are still useful in a code like this.

public function price(Quantity $quantity, Amount $amount, \Addable 
...$additionalCosts)
{
$otherCosts = array_reduce(
$additionalCosts,
static fn (int $total, \Addable $cost) => $cost + $total,
0
);

return ($amount / $quantity) + $otherCosts;
}

Regards,
Faizan

Reply via email to