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

Reply via email to