# Extension generalizing inheritance?

This topic is 4172 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Inheritance is plainly simple: you take a class (Base), add data and methods on top of it, modify the behaviour of existing methods, and you obtain a new class (Derived). Thus, it is a compile-time decoration of a given type. What about runtime decoration of any subtype of a given type? Extension (this is how I call it, for lack of a better word) takes a class (Base), adds data and methods on top of it, modifies the behaviour of existing method, and provieds a new class (Extended). Except that the extension builds on top of the polymorphic type Base, instead of monomorphic. This allows:
Base b = new Base;
Derived d = new Derived;
Extended e1 = new Extended(b); // extend b
Extended e2 = new Extended(e1); // extend e1
Extended e3 = new Extended(d); // extend d

By all means, any Extended is-a Base (because somewhere, in there, there will be a Base). However, the extension code/data can be added on top of any object which satisfies the Base signature. And besides, you can even add it at runtime (you don't have to build an entire Derived class including its base: you simply add the extension on top of the base class). I'm pretty sure this already exists, has a clear name, has detailed advantages/disadvantages and is implemented threefold in CLOS. Can you give me pointers to that kind of resources?

##### Share on other sites
To me, this sounds a lot like the Decorator design pattern, though honestly, this is one pattern I'm not as familiar with.

##### Share on other sites
Quote:
 Original post by RainaultTo me, this sounds a lot like the Decorator design pattern, though honestly, this is one pattern I'm not as familiar with.

The main problem I have with the Decorator pattern is that without some unusual contraption a Decorator is-not-a Component (and definitely isn't in the general formulation). This makes decorating a decorated decorator difficult.

Forget I said that.

##### Share on other sites
Quote:
 By all means, any Extended is-a Base (because somewhere, in there, there will be a Base). However, the extension code/data can be added on top of any object which satisfies the Base signature. And besides, you can even add it at runtime (you don't have to build an entire Derived class including its base: you simply add the extension on top of the base class).I'm pretty sure this already exists, has a clear name, has detailed advantages/disadvantages and is implemented threefold in CLOS.
Well, you immediately run into the diamond problem: the extension overrides some methods in the base class. When you're extending a derived class which also overrides one of the methods the extension overrides, which method is applicable?

Is this different from multiple inheritance?

What problem do you want to solve?

##### Share on other sites
Quote:
 Well, you immediately run into the diamond problem: the extension overrides some methods in the base class. When you're extending a derived class which also overrides one of the methods the extension overrides, which method is applicable?

In your example, the extension method would be called. An extension is, after all, a runtime derived class of whatever type the extended object is, so its methods take precedence (as would happen if the extension had been declared as a derived class at compile time).

Quote:
 Is this different from multiple inheritance?

Yes. Multiple inheritance creates a type that can have two unrelated supertypes. Extension only allows a single supertype (albeit polymorphic). Conversely, multiple inheritance is performed at compile-time, while extension is done at runtime.

Quote:
 What problem do you want to solve?

None.

##### Share on other sites
I've used the Decorator pattern a lot in implementing filter chains in C++. It's less useful for that in functional languages, though, since it's basically just a band-aid over C++'s lack of functional features.

##### Share on other sites
I've had the same idea, also to solve no particular problem. Oddly enough.

I think you can get something close (i.e. without the need for manual delegation t o the parent) if your base is a Pimpl and you then inherit from both the base (virtually? privately?) and the base-implementation. That's seriously ugly, though.

##### Share on other sites
Sounds a bit similar to the prototype pattern and prototype-based languages. The CRT pattern (in C++) also comes to mind.

##### Share on other sites
Quote:
 In your example, the extension method would be called. An extension is, after all, a runtime derived class of whatever type the extended object is, so its methods take precedence (as would happen if the extension had been declared as a derived class at compile time).
Well, that's not very nice because any specialized behaviour in any derived class method that is overriden is lost by extending it. So you have to be careful that the new extension behaves well in all derived classes you want to extend.

Thankfully, CLOS provides a better way of extending classes by providing :around, :before and :after methods that run (as their name suggests) before, after and around the methods they're put into. So you get to keep the behaviour of the derived class's method while still telling it to do something more.

This actually IS extending, rather than simply overriding as in your original proposal, and can be tremendously useful. I'll give a simple example in an hour or so if you have the patience to wait.

##### Share on other sites
Quote:
 Original post by Anonymous PosterWell, that's not very nice because any specialized behaviour in any derived class method that is overriden is lost by extending it. So you have to be careful that the new extension behaves well in all derived classes you want to extend.

You still have access to the extended class from the extending class as a "base" member, just as if you had only inherited from it. The base member has a static type of Base, but its dynamic type can be something else (and calling a polymorphic function on it will use the dynamic type).

Quote:
 Thankfully, CLOS provides a better way of extending classes by providing :around, :before and :after methods that run (as their name suggests) before, after and around the methods they're put into. So you get to keep the behaviour of the derived class's method while still telling it to do something more.

Using the syntax of my current programming language project (which provides this behavior — procedure overloading uses the runtime type of the argument):

class A {} // The base class class B extends A {} // The "extension"class C extends A {} // The class with "lost" behaviourproc Frobnicate(A _) { print( "A" ); }proc Frobnicate(B b) {  print("This happens before");  Frobnicate (b.base);  print("This happens after");}proc Frobnicate(C _) { print( "C" ); }proc main() {  b = new B { base = new C {} };  Frobnicate(b);}

This would alter the functionality of C by placing some display around the call, resulting in an output of:

This happens before
C
This happens after

##### Share on other sites
I can't see how C loses any more behaviour than B: their declarations are identical.

You still seem to explicitly disambiguate the method by calling the old frobnicate with the correct type from within the new one. It seems a lot of work keeping track of particular types. I'm not really in the mood to try to second-guess your made up syntax any further. :)

Here's how one does something similar using lisp's clos.

Suppose you have a generic animal class, and a lion class that inherits from the animal. All animals have names and sounds they make; a lion has an additional 'hungry' slot that tells us if it is hungry.

Roaring makes lions hungry, so when a lion makes a sound we have to set the hungry slot to true. We accomplish this by adding an :after method that does this to the lion's standard make-sound method.

(defclass animal ()  ((name :initform "Unknown animal")   (sound :initform "Unknown sound")))(defmethod make-sound ((self animal))  (with-slots (name sound)    self    (format t "~%~a~%" sound)))(defclass lion (animal)  ((name :initform "Lion")   (sound :initform "Roar")   (hungry :initform nil)))(defmethod make-sound :after ((self lion))  (with-slots (hungry)    self    (setf hungry t)));; let's test it[5]> (defvar an-animal (make-instance 'animal))AN-ANIMAL[6]> (defvar a-lion (make-instance 'lion))A-LION[7]> (make-sound an-animal)Unknown soundNIL[8]> (make-sound a-lion)RoarNIL[9]>

Now, suppose we run our program and see that an animal is making a sound it shouldn't make, but we don't know which animal it is. So we place a :before method on ALL make-sound methods with a base class of animal. Notice we touch neither the original class definitions nor the original method definitions. We don't care about them at all.

We do this without recompiling at all: the previously defined an-animal and a-lion instances are still in memory, with their state intact. We're adding the new method on the go, runtime.

We also don't have to worry about the type of the particular instance we are calling from (we just care if it is a subclass of animal, because all animals make sounds even if they do other things as well).

It being a :before method guarantees that the methods in the derived classes behave exactly the same as long as our :before method doesn't mess with instance state. This is nice for debugging without having to touch the class or method definitions at all, for example:

(defmethod make-sound :before ((self animal))  (with-slots (name)    self  (format t "~%Debug: the animal that is about to make a sound is: ~a~%" name)));; Now let's see what happens[10]> (make-sound an-animal)Debug: the animal that is about to make a sound is: Unknown animalUnknown soundNIL[11]> (make-sound a-lion)Debug: the animal that is about to make a sound is: LionRoarNIL[12]>