On Tue, 22 Sep 2009 20:07:22 -0400, Andrei Alexandrescu
<[email protected]> 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?
http://d.puremagic.com/issues/show_bug.cgi?id=3075
I thought Walter didn't want contravariance, maybe my clue was Walter
saying: "[Contravariance is] an attractive idea, but it's been considered
and rejected a couple of
times now."
But he may just have been talking about only doing contravariance on
delegates, maybe he's all for contravariance in the general case, but I
didn't think so.
I think the bug above is the killer example, implicit casting of delegates
would be *awesome*.
BTW, I don't see a huge benefit from your example. If B inherits from A,
then B knows about all the types A knows about (imagining an example where
the parameters were some other class hierarchy, like C and D), so does it
make a lot of sense to limit the arguments to B.fun to a base class of
something B must already know about? I mean, it's not like B doesn't know
about the derived type, how hard would it be to just use the derived
type? Maybe I'm missing something...
The other part of contravariance which bearophile brought up a while back
is contravariance (and covariance) of template parameters, that would also
be useful, but would require some annotation.
e.g.:
class C(in T) // means compiler enforces that C only ever uses T as an
input
{
void foo(T) {...}
}
class A {}
class B: A {}
void fun(C!B c) { auto b = new B; c.foo(b);}
void main()
{
auto c = new C!A
fun(c); // legal
}
A good example for C would be a comparator object.
But I think the absolute best usage is implicit delegate casting. That
should be a no-brainer in my mind.
-Steve