

The impoliteness of overriding methods - munificent
http://journal.stuffwithstuff.com/2012/12/19/the-impoliteness-of-overriding-methods/

======
jonathlee
To the best of my knowledge Common Lisp methods (CLOS) already allows the
ability to do things such as your rendering co-ordinate transformation example
already without requiring extraneous abstract method definitions.

Generic functions and their associated methods allow :before, :after and
:around qualifiers to be added to specify the order in which they are run
without the need of creating secondary method names for each layer of
subclasses. For base class methods that need code to be run before or after
the more-specific subclass method is called, a :before/:after method(s) is
written that will be executed before the more-specific subclass "overridden"
unqualified method is called. The developer of the subclass doesn't have to
care/know that the base class is still doing some work there.

Conversely, if this base :before method needs to be modified, it too can be
overridden with a corresponding :before qualified method (with/or without a
call back to the base :before method via call-next-method) or even totally
shadowed by an :around qualified method in the subclass.

This seems to be the best of both worlds. The original base class developer
can specify code that needs to be executed for each overridden method without
the sub-class developer needing to be aware of it without handcuffing the sub-
class developer in handling edge-cases that the base-class developer didn't
foresee.

Here is the example code that implements this:

    
    
      (defclass game-object ()
        ((x :accessor x :initarg :x :initform 0)
         (y :accessor y :initarg :y :initform 0)))
      
      (defmethod set-transform (renderer x y)
        ;; set the renderer coordinates here.
        )
      
      (defmethod draw-image (renderer image)
        ;; draw image here
        )
      
      (defgeneric render (game-object renderer)
        (:documentation "Render GAME-OBJECT to display using RENDERER."))
      
      
      (defmethod render :before (game-object renderer)
        (set-transform renderer (x game-object) (y game-object)))
      
      (defmethod render (game-object renderer)
        (draw-image renderer game-object))
      
      ;; Class where the :before base class method just runs
      (defclass scary-monster (game-object)
        ((image :accessor image :initarg :image)))
      
      (defmethod render ((game-object scary-monster) renderer)
        (draw-image renderer (image game-object)))
      
      ;; Class where the :before base class method is prevented from running
      ;; to prevent some undesirable action.
      (defclass happy-monster (game-object)
        ((image :accessor image :initarg :image)))
      
      (defmethod render :around ((game-object happy-monster) renderer)
        (draw-image renderer (image game-object)))
      
      ;; REPL session with the RENDER, SET-TRANSFORM and DRAW-IMAGE methods traced
      CL-USER> (render (make-instance 'scary-monster :x 1 :y 2 :image 'a) nil)
        0: (RENDER #<SCARY-MONSTER {2456D3F1}> NIL)
          1: (SET-TRANSFORM NIL 1 2)
          1: SET-TRANSFORM returned NIL
          1: (DRAW-IMAGE NIL A)
          1: DRAW-IMAGE returned NIL
        0: RENDER returned NIL
      NIL
      
      CL-USER> (render (make-instance 'happy-monster :x 3 :y 4 :image 'b) nil)
        0: (RENDER #<HAPPY-MONSTER {246A1689}> NIL)
          1: (DRAW-IMAGE NIL B)
          1: DRAW-IMAGE returned NIL
        0: RENDER returned NIL
      NIL

------
michaelfeathers
Nice.

One metaphor that I like to use in OO is that inheritance is best used to
"fill in holes." Imagine that an abstract class is a class with holes in it
(i.e., the abstract methods). Subclassing fills in the holes and gives you a
complete class. That is really the best use of inheritance. If you override,
you have a higher chance of breaking behavior via a Liskov Substitution
violation.

~~~
st0p
You mean the template pattern as described in GOF? Very nice nice and
underused pattern, but sometimes it is better to use some event based system
as mentioned in the article and sometimes it is better to just be rude and
overwrite a method (very nice metaphore BTW).

More "traditional" OO like C++ or Java let the developer choose. The
"traditional" way gives you more flexibility and more ways to shoot yourself
in your foot.

~~~
MartinCron
_You mean the template pattern as described in GOF? Very nice nice and
underused pattern_

The template pattern was when I finally "got" design patterns, realizing that
they were ways of describing and communicating (some) things that I was
already doing.

------
cpeterso
Overriding virtual functions is a huge hole in information hiding.

In C++, the "Non-Virtual Interface" (NVI) design pattern recommends that
interface classes declare nonvirtual public functions that delegate to private
pure virtual functions to be implemented by derived classes. A base class
destructor should be either public and virtual, or protected and nonvirtual.
NVI allows the base class to add pre- and post-condition assertions to test
the derived implementation classes. NVI should also alleviate the "fragile
base class" problem with C++ binary compatibility.

[https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Non-
Virtua...](https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Non-
Virtual_Interface)

------
jlongster
This is an interesting concept. I've recently been working on 3d engines and
games and found the typical subclassing behavior broken like he describes.

The Entity-Component-System architecture I think largely solves my problem,
though. After I finish my current game I plan on reflect on better ways to
structure the data, so it's good to have this idea in mind. Thanks.

------
draegtun
Moose (<http://moose.perl.org>) also provides the same mechanism via
_augment/inner_.

Here is one of the examples in Perl/Moose:

    
    
      package GameObject {
          use Moose;
          has ['x', 'y'] => (is => 'rw', isa => 'Num');
    
          sub render {
              my ($self, $renderer) = @_;
              $renderer->set_transform( $self->x, $self->y );
              inner;
          }
      }
      
      package ScaryMonster {
          use Moose;
          extends 'GameObject';
      
          augment render => sub {
              my ($self, $renderer) = @_;
              $renderer->draw_image(Images->scary_monster);
          };
      }
    

refs:

\-
[https://metacpan.org/module/DOY/Moose-2.0604/lib/Moose/Manua...](https://metacpan.org/module/DOY/Moose-2.0604/lib/Moose/Manual/MethodModifiers.pod)

\-
[https://metacpan.org/module/DOY/Moose-2.0604/lib/Moose/Cookb...](https://metacpan.org/module/DOY/Moose-2.0604/lib/Moose/Cookbook/Basics/Document_AugmentAndInner.pod)

------
jashkenas
Two follow-up questions for you, Bob:

Do you think it would be wise to implement inner() (perhaps alongside the
existing super()) for Dart?

If so, would there be a decent way to do the implementation for the compile-
to-JS version, given that there's no native JavaScript way refer to things
_down_ the prototype chain instead of up?

~~~
munificent
_Do you think it would be wise to implement inner() (perhaps alongside the
existing super()) for Dart?_

I think it would be neat, but it's very unlikely to happen. I'm not one of the
language designers. Lars and Kasper are and they've both implemented BETA VMs,
so they're certainly aware of inner() and decided not to go in that direction.

 _If so, would there be a decent way to do the implementation for the compile-
to-JS version, given that there's no native JavaScript way refer to things
down the prototype chain instead of up?_

If you can statically tell your inheritance chains (i.e. at compile time you
know what your superclass is), it should be pretty straightforward, I think.

    
    
        class A {
          foo() {
            before();
            inner();
            after();
          }
        }
    

You'd compile the above to something like:

    
    
        function A() {}
        A.prototype.foo = function() {
          before();
          this.$A_foo_inner();
          after();
        }
        A.prototype.$A_foo_inner = function() {}
    

And a subclass like:

    
    
        class B extends A {
          foo() {
            console.log('In B!');
            inner();
          }
        }
    

Gets compiled like:

    
    
        function B() {}
        B.prototype.$A_foo_inner = function() {
          console.log('In B!');
          this.$B_foo_inner();
        }
        B.prototype.$B_foo_inner = function() {}
    

I think something like that would work, but I haven't put much thought into
it. The critical bit is being able to tell at compile time that the foo() in B
is an override so that you know to compile it to $A_foo_inner and not just
foo().

------
killahpriest
Shouldn't it be this.balance ?

    
    
        var account = {
          balance: undefined,
          deposit: function(amount) {
            return balance += amount;
          }...
        }

~~~
masklinn
In javascript yes. Munificent probably got a bit confused with java (that's
what he seems to be using in the rest of the post, and from what I remember
it's his historical go-to language) or with Dart (I don't know if dart
mandates `this` for self-attributes)

~~~
munificent
Ha, yes, you're exactly right. I'll fix that in the post. :)

Dart does indeed allow you to omit "this." which is really really nice.

------
dougk16
Another way to solve this problem in theory is to have Java-like annotations
that force subclasses to call super whether they like it or not, and even
where they must call super, for example @OverridesMustCallMe(location="top").
The super call could be automatically added at compile time if you don't
provide it, or it could result in a compiler error if you don't provide it
(probably the latter). Never seen a language like this though, so it may be a
bad idea for some reason.

------
JoeAltmaier
A simpler mechanism is a keyword to declare a derived function as recursive,
either head or tail. They would be similiar in behavior to ctor and dtor
methods e.g. in C++. The idea is, to extend the existing execute-base-first
behavior of C++ constructors, and execute-derived-first behavior of
destructors, in a way that can't be overridden.

Less utility, but simpler to explain and already implemented, at least in some
languages.

------
betterunix
I wonder if this is an issue that can be addressed using a metaobject protocol
-- change the way methods are dispatched and if, when, and how they can be
overridden.

------
throwaway54-762
Upvoted just for "// Service charge, sucker!"

