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

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.

  • Comment on Re: Re: Re: Class::Interface -- isa() Considered Harmful

Replies are listed 'Best First'.
Re: Re: Re: Re: Class::Interface -- isa() Considered Harmful
by djantzen (Priest) on Jan 16, 2003 at 08:07 UTC

    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;

        You're right, there is no formal definition of an object, and there is no single form of object orientation. However, the requirement that an object combine state and behavior is sufficiently general as to be acceptable to nearly everyone, from Smalltalk programmers who would want to talk about behavior as message passing, to C programmers who write functions that take struct pointers as initial arguments.

        The reason languages do not allow inheritance of state without behavior is that it runs counter to the goal of encapsulation. Whether you're doing straight function coding or working on a deep OO tree, encapsulation is basically always a good idea. To take the guts out of a subroutine or object and toss away the abstraction layer provided by the interface is to take a step in the opposite direction of ease of development, maintainance, sanity :)

        A better way to get at the separation of state from (certain) behavior is to look at something like the classic model-view-controller pattern, where you've got all your state wrapped up in one class, methods for manipulating the state in your controller class, and a presentation layer in the view class. Thus you've got separation and encapsulation, and you haven't introduced this new burden of manually coordinating state and behavior which in the vast majority of cases the programmer is not going to need or want.

Re^4: Class::Interface -- isa() Considered Harmful
by Aristotle (Chancellor) on Jan 18, 2003 at 12:31 UTC
    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.