contravariant argument types: wanna?

Steven Schveighoffer schveiguy at yahoo.com
Tue Sep 22 18:15:54 PDT 2009


On Tue, 22 Sep 2009 20:07:22 -0400, Andrei Alexandrescu  
<SeeWebsiteForEmail at erdani.org> 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



More information about the Digitalmars-d mailing list