Object-Oriented Programming is the Dual of Functional Programming
Let's take a quick look at programming from an interesting perspective. Let's say that programs are divided into code and data. ^1 These are the two main axes: structuring code and structuring data.
Now, let's design a language. First decisions: which axis is primary, which is secondary?
Style Data Code
OOP Primary Secondary FP Secondary Primary
In an OOP-style approach, we have a pointer to an object which is the data. And the data also tells you where the code is to access it (methods in the vtable). An FP-style approach will make functions (code) primary, with data referred to by the closures (the captured lexical environment).
I'm positive I'm not the first person to remark on this, but I think it's pretty cool that they are duals of each other. A simple transformation will switch one in the table with the other.
Perhaps the next obvious question is "which one is better?". Many arguments about OOP vs FP focus on this choice, about which axis should be primary. Because a compiler could easily transform between them, the decision is not quite so important as we might think at first. I think that a language should make both available and let the programmer choose. The programmer is then free to choose whichever best models the problem.
For instance, in Clojure, fns are closures, so they are really FP-style --- code meant to be executed which happens to refer to some data. But collections are data which refer to code which knows how to access the data. Both coexist quite cooperatively.
And Clojure gives you, the programmer, ways of expressing both
styles. When you want to create some code to be executed,
you define lexical closures. But sometimes you want to make a new data
structure which acts like others. For instance, a new type of
deftype lets you
define data with interface and protocol implementations. I use both
deftype very often.
function defines lexical closures, making code primary. But very often
you define an object which contains (or refers to) data and secondary
How does your language prioritize these two axes? Is there a way to choose which to use to best implement your design? If you're interested in this kind of topic, you would probably enjoy the Clojure Gazette. It's a weekly newsletter filled with content to inspire Clojure programmers. It's completely free and it's easy to unsubscribe.
- I don't want to go down the code-is-data rabbit hole. Let's stick to one floor in the tower of languages model.