Interface Normalization

This is another lesson that does not require functional programming to notice, but it is a lesson that functional programming puts front and center whereas independently discovering it from imperative programming may take a long time.

Functional programming derives (pun intended) a lot of benefit from its typeclasses, despite them in some sense being second-class citizens in the expression problem to sum types. Much code is written against small interfaces like “functors” or “monads”, which can then be applied to any value that fits into those interfaces. This is one of the important ways that functional programs can have polymorphism.

Obviously, object oriented programs can also have polymorphism. For the purposes of this functional programming language lesson, “object oriented” is going to include “inheritance”. Normally when discussing in a cross-language context I use a very loose definition of “OO” to be basically “some way of bundling data with methods”, which includes Go (no inheritance) and prototype-based Javascript from before the class keyword, and while this may apply somewhat to such languages, the point will be made most clearly by inheritance-focused imperative languages.

Polymorphism is a primary goal of object orientation, obtained through the subclassing relationship. It may offer others, such as the way interfaces can be added on to an OO system fairly cleanly in various ways, but it is guaranteed to at least have polymorphic subclass relationships; being able to pass CDerived to a function or method expecting a CBase is the entire point.

Subclasses can only add to their parent’s class1. As objects become arranged into their various hierarchies, and things get subclassed, it also tends to tie up the parent classes such that changes to them become increasingly difficult due to the scope of the code that the changes would affect, because all changes to a parent class affect all subclasses. This is assuming you can change parent classes at all, since they may be coming from a 3rd party library you don’t want to or can’t fork.

Consequently, OO languages afford a style where details get pushed down the hierarchy. The larger the hierarchy, the more the details end up pushed down as the parent classes tend to become more and more abstract. Thus, while you may nominally have something like a QObject in the QT library, most code is going to take something more specific, and usually, much more specific.

This is difficult to express, but a result of all of this is that an OO designer will tend to develop a design approach where everything in a class has a very specific purpose, and anything that can be pushed down the hierarchy is pushed down the hierarchy, because maintaining things at higher levels becomes more and more difficult as more subclasses hang off of them. Anything that appears in a higher level must be directly applicable to all classes that may inherit from it, not just today, but someday in the indefinite future.

This is not, on its own, a bad thing. The logic I spell out here is valid on its own terms. But it is not the only approach.

Typeclasses in functional programming derive much of their power from going the other way, though, creating interfaces that you can use to operate on things, such as “monad”, and then expanding the reach of those interfaces by happily implementing degenerate implementations of those interfaces where it makes sense.

That is to say, in OO, if a class inheriting from its base class generally had better use all of the base class’ functionality. If it doesn’t, it is probably inheriting from the wrong base class. The “correct” base class may even have to be constructed by tearing the parent apart into multiple base classes, creating those very “abstract” classes that such systems tend to create.

Typeclasses, by contrast, lend themselves well to degenerate implementations of interfaces. “File” interfaces with Close methods that do nothing, for instance, are very useful. Or one of the classic confusing things about monads, “monad” interface implementations that are just degenerate upgrades of a Functor. As noted in my monad “tutorial”, one of the problems people have with understanding “monad” is precisely that the examples people reach for tend to be these degenerate examples, many of which are actually just functors, and using those as your primary examples makes it very difficult to see what the “monad” is actually enabling.

Object oriented programming naturally affords splitting things into hierarchies, making sure that nothing extra appears at any layer. Functional programming derives a great deal of power by flattening things into common interfaces and then writing very generic code against those common interfaces.

Once again, it is difficult to do this at the same level of granularity as a full-on functional programming language allows, as evidenced (if not outright proved) by all the failed attempts to bring ergonomic “monad” implementations into so many imperative languages, but the principle can be carried into OO quite easily at slightly higher levels. I have long since made my peace with interfaces where some of the methods have a defined way of saying “not applicable to this value”, or that may have what are effectively stubs in many, even most of the implementations.

There are OO answers to this; for instance one of my favorite patterns in general (when translated into the local idiom) is the Template pattern, which in OO terms involves creating a superclass that has stub methods for subclasses to fill in that describe how to do certain things, and then code can be written against the superclass that will “do the right thing” for whatever child is passed to it. A common example is simple image manipulation code that may allow you to, say, crop and rotate an image directly, then templates can be filled out for various bit depths, alpha depths, or depending on how aggressive you are being, perhaps will even implement something like very lossless cropping for JPEGs if the requested crop permits it, but everywhere else just does the obvious pixel manipulations and saves it as normal.

On the one hand, Template is nominally a perfectly normal OO pattern that has been in the Gang of Four book since the beginning of “design patterns” as a concept, which itself means it was already in common use before that… and on the other, it is a pattern I have not seen utilized very often in the wild, and I have personally worked with developers who had to have this concept of leaving in method plugin points that some derived classes may not use explained to them, not even because they can’t understand it, but just because using OO languages tends to leave you with a blind spot here. Methods in a superclass that most classes do not use cuts strongly against the training that OO tends to give you that you should have nothing extraneous anywhere because that extraneous stuff will bite you later. It takes a certain amount of swimming against the current of OO to figure this out, but a functional programming language will serve it to you cleanly.

Once you have it, no matter how you have derived it, it is a powerful tool to add to the toolchest.


  1. I mean, you can hack something where you subclass a method and implement it by unconditionally throwing an exception or something, but generally that’s a bad idea and only to be used in desperation. If you program in an OO language, you should learn the Liskov Substitution Principle. And then recognize that in practice it is a principle broken as often as it is followed… but your OO programming can still improve for at least being aware of it. ↩︎