When building inheritance hierarchies in object-oriented languages, it is often desirable to have methods that are not implemented by the base class but only by the leaf-level classes in the hierarchy. A common case is when using the Template Method pattern.
These methods are called abstract methods.
How do we mark methods as abstract? That depends on the language we’re using.
In Java, there is an
abstract keyword, and we must mark both the
method and its containing class as abstract:
In C++, abstract methods are marked as pure virtual methods:
Java and C++ both require that abstract methods be declared in the base class; otherwise, we can’t call them via a reference to the base class.
Dynamic languages have no such restriction; neither Smalltalk nor Ruby requires abstract methods to be declared. In fact, neither language even provides the syntax for doing so.
Even though Smalltalk doesn’t provide syntax for abstract methods,
its class library does provide the
If we attempt to send
myMethod to an object that doesn’t implement
subclassResponsibility raises a runtime error. Also, the code
editor in many Smalltalks indicates abstract methods (and other
unknown methods) using some form of in-place notation such as red
squiggly underlines. In addition, the class creation dialog in
Visualworks Smalltalk can optionally create skeleton implementations
of all subclass responsibility methods from the ancestors of the new
So even though Smalltalk doesn’t require that abstract methods be declared, it does provide several affordances that encourage us to do so.
Ruby does not provide these affordances. Certainly, it is possible to do part of it ourselves:
This works fine, and I’ve seen this pattern quite a bit. But many Ruby programmers don’t bother declaring abstract methods at all.
It would be pretty easy to extend Ruby with a Smalltalk-like mechanism:
So what’s the point? Is it really worth declaring abstract methods like we’re forced to in Java and C++?
In my opinion, it is well worth it because of the communication value.
I can look at a class I might want to inherit from (or a module I might want to include) and know at a glance which methods I need to implement. Also, when reading the code in the base class, I can easily see where the called methods are defined or declared.
When a language provides affordances for abstract methods, we’re more likely to declare them. The consistency of the affordance also makes it easier to find abstract methods using grep or a more targeted search provided by our development environment or IDE.