in reply to Re: Class::Interface -- isa() Considered Harmful
in thread Class::Interface -- isa() Considered Harmful

All this is to set up my conjecture which is that maybe we should talk about two kinds of inheritance. For lack of a better word, one would be "behavior" inheritance (all objects must be able to "hit the thing") and the other "property" (data) inheritance (all objects must be able to tell me their weight in kilograms).

I'm close to agreeing with you, and I think the idea can be clarified to answer chromatic precisely. The two types of inheritance are inheritance of interface and inheritance of implementation. The former indicates that the object at hand will respond to the same method calls as its superclass, whereas the latter means that the object will accomplish those tasks using the same code and in the same manner as its parent class. I disagree with the idea that if a subclass merely supports an interface but does not inherit (at least some parts of) its implementation that it lacks an is-a relation with its superclass. A class that implements an interface inherits the public feature set of its parent class and its parent class's type.

For comparison, look at the concept of the "abstract base class" stemming from C++ and its later evolution to Java interfaces discussed in this recent interview with Scott Meyers, one of the C++ gurus. As a way of avoiding nasty conundrums resulting from C++'s allowance for multiple inheritance, Meyers has argued in his books that a subclass should inherit its implementation from only one of its superclasses. Additional superclasses should be abstract base classes (ABCs) with no data members and only pure virtual functions. In other words, an ABC can at best be instantiated as an empty shell, and its methods declared but not given any bodies and their implementations looked up at runtime in declared subclasses. Thus, all that such classes provide are additional is-a relationships. Java provides shorthand for this with the interface keyword, which guarantees what C++ coders had to see to for themselves. For this reason, placing an interface in a class's @ISA makes perfect sense; it's just rather close to the C++ way.

Replies are listed 'Best First'.
Re: Re: Re: Class::Interface -- isa() Considered Harmful
by autarch (Hermit) on Jan 16, 2003 at 06:59 UTC

    Yep, I thought of Java interfaces versus the single "implementation" parent.

    I was thinking of going further. First of all, support Date & Darwen's inheritance model (which is all about inheriting attributes) which includes MI. Define implementation inheritance to not cause the inheritance of implementation. This is what Java interfaces, and chromatic's proposal suggest. Finally, forbid inheritance of interfaces from implementation parents! This last bit is what I think may be a new idea (or at least not present in C++, Java, and certainly not Perl).

    I do think calling it implementation inheritance is a bit confusing, since you're really inheriting attributes (or properties). The actual internal implementation may or may not change in the subclass.

    So if you had a class Car that inherited implementation from WheeledLandVehicle (which may in turn have inherited from some other class), it'd have to provide access to certain attributes such as weight, manufacturer, number_of_wheels, and so forth.

    Interface-wise, Car might inherit interfaces such as Steerable, CanChangeVelocity, Breakable, and so on.

    I should also point out that in the model I'm thinking of, nothing would preclude inheriting both interface and attributes from the same class, which is obviously going to be a common need. But at the same time, when you don't need, or want, to do that, you wouldn't have to.

      I do like the idea of an explicit mechanism in Perl to declare that a class provides its own implementation for an interface, since as it stands now you must search @ISA for the abstract base class and then at runtime see if those methods actually permit themselves to be used. (Note that it's common to die or throw an Exception or Error inside those "abstract" methods in the case they are called directly or not overridden in subclasses.) I think this is sound theoretically -- I reiterate that inheritance of interface constitutes an is-a relationship -- however it is a pain. What I'd like is to say:

      use base Car; use interface Drivable; # a little cleaner than chromatic's example co +de IMHO

      and have the interface pragma enforce the proscription against non-static data members and method implementations. Discovering if a class implements an interface then is the simpler task of querying the implements hash or array.

      The major obstacle to acceptance of the Date & Darwen idea of inheritance is that it's not what most programmers mean when they talk about object-orientation. The definition of an "object" is the synthesis in a single entity of state and behavior. I have no objection to the judicious separation of these two things into i.e., structs or class methods, however a class with methods but no instance data does not define an object, and neither does a class with data but no methods. (Hmm, "Methods without data are empty, data without methods are blind" :^) This is why I'm saying that "implementation" covers all aspects of how a class does its business, including not just the data members, but the member functions as well. Now if all you want out of an object is its data, then subclassing is inappropriate; rather, you should simply pull what you need from the object and store it elsewhere, where you don't need to ensure that it won't be acted upon using its natural inherited behavior.

        The major obstacle to acceptance of the Date & Darwen idea of inheritance is that it's not what most programmers mean when they talk about object-orientation. The definition of an "object" is the synthesis in a single entity of state and behavior. I have no objection to the judicious separation of these two things into i.e., structs or class methods, however a class with methods but no instance data does not define an object, and neither does a class with data but no methods. (Hmm, "Methods without data are empty, data without methods are blind" :^) This is why I'm saying that "implementation" covers all aspects of how a class does its business, including not just the data members, but the member functions as well. Now if all you want out of an object is its data, then subclassing is inappropriate; rather, you should simply pull what you need from the object and store it elsewhere, where you don't need to ensure that it won't be acted upon using its natural inherited behavior.

        "The definition of an object"? I don't think there's any single formal, well-defined definition of what an object is. This is exactly why Date & Darwen explicitly avoid ever using the word object, and just talk about data types.

        Now, it's certainly the case that many informal definitions of what an object is assume that it combines state and behavior. I'm not entirely opposed to this. I'm simply proposing that it might be advantageous to separate the inheritance mechanisms for state and behavior from each other. To a certain degree, this is possible in many languages, which allow you to inherit behavior (interfaces or a virtual parent class) without inheriting state.

        What I'm speculating on is the possibility of inheriting state without behavior, which in theory could be done by inheriting from a class that only implemented "state-access/update" methods. I'm further speculating on the idea that a language that had different syntax and inheritance mechanisms for these two might be useful. For example, I might do "object->do_something" for behavior and "object.size" to access an attribute. And both of these would be valid ways to use the object. Furthermore, there'd be syntax for two kinds of inheritance, so we might do:

        class TalkingSword : state -> Weapon /* inherits state from RPGObject +class */ : behavior -> EdgedWeapon, Speaks;

      I think what you mean is to separate implementation of interfaces from the implementation of attributes they manipulate. Yes, that's a good idea. However, it's too blurry a line in my opinion, so is not something the language can enforce. Rather, it's the framework designer's homework. The model-view-controller paradigm fever mentioned seems indeed to be what you're after. In fact, I consider the MVC approach almost the sole raison d' être for OO as a paradigm equal to functional or logical programming.

      Makeshifts last the longest.