contravariant argument types: wanna?

Andrei Alexandrescu SeeWebsiteForEmail at erdani.org
Wed Sep 23 08:13:26 PDT 2009


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



More information about the Digitalmars-d mailing list