Composition and inheritance: the Julian way

Object-oriented programming is oriented around objects. Duh. But what that means is that it’s oriented around data and its representations. You need inheritance in order to make more generic code work because all of your functions are written according to some data layout. Your ideas about “an algorithm” is abstract, and your concrete implementations intermingle the ideas of the internal data and its representations.

Typed-dispatch programming, or multiple dispatch programming, or action-oriented programming flips this around. The pseudocode algorithm is exactly what becomes your code. It’s a generic function and any instantiation of that algorithm specializes on the input types to add in the actual underlying handling of data. In this case, the function or the algorithm is the core idea, and the data’s representation is what is held abstract throughout most of the programming. This comes natural to Julia through multiple dispatch, where you can write an algorithm that does A*x and not care what kind of matrix A is, since in the actual mathematics you don’t assume that A is a sparse matrix represented in CSC form, that’s just a computer detail!

The only time in this kind of programming that you have to deal with it is when you’re defining a new type and its primitive functions. Even then, in most types you’re building a composite type, i.e. building a new type from pieces, and so the primate functions are really just the actions on underlying data. So A*x on MyArray should really be A.A*x, so I forward it along. For this reason, composition with parametric types is a very natural way to do extension because once again I don’t have to care about the true internal data layout of A.A. If A.A does all of the actions that I want in my extension, it’s fine! The fact that a SparseMatrixCSC has fields for colptr is not something I should have to worry about because what I care about is extending its actionability and not building a data layout. Only at the very bottom when defining bitstypes or memory buffers for arrays, or fancy things likes implementations of sparse matrices, do you actually have to care about the internals of the data layout. In most mathematics you don’t have to, so there’s no reason to inherit all of that cruft (and the rigidness that comes from being tied to a data layout), so you might as well keep A.A as its own box that can change at any time as long as it acts the same. This is why composition makes sense in Julia programming, especially when going to generic codes.

10 Likes