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?