contravariant argument types: wanna?

Jeremie Pelletier jeremiep at gmail.com
Wed Sep 23 08:48:41 PDT 2009


Ary Borenszweig wrote:
> 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.)
> 
> So it should be:
> 
> class JamesBond : Driver {
>   override void drive(Object c) { ... }
> }
> 
> because JamesBond can even drive a HotGirl!

class MultiTask {
	this(Object[] tasks) {this.tasks = tasks;}
	Object[] tasks;
}
(new JamesBond).drive(new MultiTask([new Truck, new HotGirl]));

He can do both at once!



More information about the Digitalmars-d mailing list