contravariant argument types: wanna?

Andrei Alexandrescu SeeWebsiteForEmail at erdani.org
Wed Sep 23 11:01:59 PDT 2009


Jeremie Pelletier wrote:
> Have you read my other post in this thread where I show an actual 
> example of covariant arguments from my display interface, my I/O 
> interfaces also use covariant arguments although they're more friendly 
> to generic interface parameters.

I did. I don't have enough information to comment on the design, but at 
the end of the day, statically-typed OO designs should be for families 
that have many commonalities and few differences. As such, access to the 
interface should be everything needed for carrying out most tasks. 
Maintaining two parallel hierarchies in which each of them must cast 
around from the least capable to the concrete one is, I think, a design 
due for some improvement.

A derived class does not "extend" its base class. It specializes it, 
because the base class represents an archetype for a variety of types, 
including the derived class but much larger. So a Mammal doesn't quite 
"extend" Animal because Animal includes all animals, mammals and 
reptiles and whatever. If anything, Mammal narrows the inheritance cone 
from under Animal. Indeed Mammal does add state, but Animal should not 
be considered holding its state; it's holding its own state plus the 
unrealized state of any class inheriting from it.

Unfortunately many designers today are blocked in the "inheritance 
extends" view of things. They define a base class or interface first 
with a narrow set of primitives, and then they "extend" it by defining 
new methods, which works exactly against object orientation. Every new 
method that's not in the parent class is an invitation for casting and 
against reuse and genericity. Ironically, Java put that characterization 
straight in the language, furthering the legitimacy of bad designs. A 
good OO design defines abstract yet _capable_ generic interfaces that 
suffice for achieving complex goals, and then implement them in concrete 
classes. Very rarely if ever should a piece of code know the exact 
implementation of an interface.

I am considering discussing all of the above in detail in TDPL, but I am 
afraid that some refugees from other languages will be shocked.

> The point is, you see covariance all the time in interface programming 
> when implementations expect an interface argument to be an object from 
> that same implementation. As soon as you use an abstract factory to let 
> the world use some implementation without being aware of which one it 
> is, you're bound to see covariance at some point. Most people just code 
> it explicitly, the mozilla code is *full* of explicit covariant 
> interface requests.
> 
> While they may not be sound, its still a scenario you're gonna come 
> across sooner or later, and a scenario which involves lots of similar 
> boilerplate that can easily be generated by the compiler.

The "capability cast" scenario could occur now and then, but if it's too 
frequent it reflect a problem in the design, not in the language 
implementing it.


Andrei



More information about the Digitalmars-d mailing list