contravariant argument types: wanna?

Yigal Chripun yigal100 at gmail.com
Wed Sep 23 12:11:31 PDT 2009


On 23/09/2009 18:13, Andrei Alexandrescu wrote:
> Jeremie Pelletier wrote:
>> Yigal Chripun wrote:
>>> On 23/09/2009 03:07, Andrei Alexandrescu wrote:
>>>> Hello,
>>>>
>>>>
>>>> Today, overriding functions have covariant return types:
>>>>
>>>> class A {
>>>> A clone();
>>>> }
>>>>
>>>> class B : A {
>>>> B clone(); // fine, overrides A.clone
>>>> }
>>>>
>>>> That is entirely principled and cool. Now the entire story is that
>>>> overriding function may have not only covariant return types, but also
>>>> contravariant argument types:
>>>>
>>>> class A {
>>>> A fun(B);
>>>> }
>>>>
>>>> class B : A {
>>>> B fun(A); // fine (in theory), overrides A.fun
>>>> }
>>>>
>>>> Today D does not support contravariant arguments, but Walter told me
>>>> once he'd be quite willing to implement them. It is definitely the
>>>> right
>>>> thing to do, but Walter would want to see a compelling example before
>>>> getting to work.
>>>>
>>>> Is there interest in contravariant argument types? If so, do you
>>>> know of
>>>> a killer example?
>>>>
>>>>
>>>> Thanks,
>>>>
>>>> Andrei
>>>
>>> consider:
>>>
>>> class Car { ... }
>>> class Truck : Car { ... }
>>>
>>> class Driver {
>>> void drive (Car c);
>>> }
>>>
>>> class truckDriver : Driver {
>>> void drive(Truck t); // NOT contra-variant !!
>>> }
>>>
>>> does the above design will be affected by your suggestion?
>>
>> You just described covariant arguments, which is a feature i'd also
>> like to see. It's different from contravariant arguments, implementing
>> one does not give the other unfortunately.
>
> Well there's a good reason for it: contravariant arguments are sound,
> covariant arguments aren't. My belief is that a design that would need a
> lot of argument covariance ought to be analyzed.
>
> I thought more about the car/truck example and I think it can be worked
> out nicely. The problem right now is that Truck inherits Car. But a
> truck is not substitutable for a car in all instances, because for
> example a driver able to drive a car cannot necessarily drive a truck.
> Here's a design that fixes that:
>
> class AutoVehicle { ... }
> class Car : AutoVehicle { ... }
> class Truck : AutoVehicle { ... }
>
> class Driver {
> // A driver is licensed to drive a car
> void drive(Car c);
> }
>
> class TruckDriver : Driver {
> // A truck driver is licensed to drive a car...
> override void drive(Car c);
> // ... and a truck
> void drive(Truck c);
> // No contravariance needed yet
> }
>
> class JamesBond : Driver {
> // James Bond can drive any auto vehicle
> // Contravariance needed here
> override void drive(AutoVehicle c) { ... }
> }
>
> Now if what you have is a JamesBond and a Truck, you need contravariance
> to have him drive it. (A HotGirl may or may not be present in the scene.)
>
>
> Andrei

I second Andrei's point that covariance isn't sound. however, my example 
should still be valid. If you require the override keyword to enable 
contra-variance that would be OK, I think.

in my example the drive method is overloaded since we want truckDriver 
to drive Cars and Trucks.
is there an example where you'd want co-variance with overriding instead 
of overloading?



More information about the Digitalmars-d mailing list