A question developers coming into Functional Programming, from other paradigms, frequently ask is, “What is Functional Programming?”.
This generally leads to one of two responses. Either “It’s programming with functions”, or it leads into a trip down category theory.
The first answer doesn’t seem that helpful, and it’s often rebated with the argument that in OO developers also program with functions. The second one, is probably even less helpful as it tends to scare people and show FP as a dark science.
What I’m going to try to do here, is correlate how first class concepts of functional programming correlate with techniques that OO developers are familiar with. So, this tutorial is aimed at OO developers that want an answer to the “What is Functional Programming?” question.
Next, I’m going to, step by step, describe some OO techniques that have become popular through the last few years. Bear with me as this will lead us to the core of what is FP.
VOs and Entities
Typically OO advocated for encapsulating data with behaviours inside of a class. This meant that other classes depending on this data required the class to expose some of its internals, leading to tight coupling between these classes. It meant that now, all of these behaviours had to come attached even if they weren’t required, just because we needed some of the data encapsulated by this other class. This also meant that changing the implementation details of this class could break others that depended on their data.
Come Value Objects and Entities. Value Objects, are pure value representations without associated exposed behaviours. Entities are very similar except by the fact that they’re data structures that have an identity that distinguishes instances. This meant that we now could have different parts of our systems depending on these “data only” structures, without causing tight coupling to other system behaviours. It also meant that those behaviour classes didn’t need to expose their internals anymore, so were better encapsulated.
Now that we’ve split our data from our behaviour, let’s talk about another OO concept that gained popularity in the last couple of decades.
Programming to an interface
Although not directly related to the previous point, this yields the best results when the previous technique is also in place. What this gives us is polymorphism. Even though polymorphism is a concept that is mentioned frequently in programming, I feel it’s worth it to define the term here. Polymorphism comes from the ancient Greek, and means “assuming multiple shapes”. How this translates to programming with interfaces is that by depending on interfaces, you can then provide multiple implementations for that interface, and be completely implementation agnostic. This reduces coupling, and encourages encapsulation (assuming you don’t encode methods exposing the internals in the interface).
At this point, because we’ve separated data from behaviours, our classes only depend on data (VOs or Entities) and lists of methods (interfaces).
It’s now time to introduce another concept that has gained a lot of popularity in the OO community in the last few years.
What interface segregation says is, you should split the methods in your interfaces into small interfaces and then assemble them into larger ones, by having interfaces extending others. This means classes will depend strictly on the methods that they require rather than depending on list of 20 methods when the only need 1 or 2 of those methods. If you take this segregation far enough, you will end up with a bunch of 1 method interfaces and implementations that depend on multiple interfaces for composed behaviour.
So let’s talk about another concept that is now widely used in OO programming, called dependency injection.
For any of this to be of any use, implementations of these composed interfaces can’t be created inside of your classes (well, they can and will, but in some special classes that live at the boundary of your program, not in just any class). So, you have to inject it. This basically means you have a part of your system that orchestrates which implementations of these interfaces you need, and then wire them together in a way that satisfy the interface dependencies.
So how does this relate to FP then?
In short, what I just described, is what FP is.
Functional languages usually provide some way to natively represent pure values. In Scala this would be case classes and case objects, in Haskell these are just that, values (In Haskell there’s only the concept of values, no classes or objects).
If you think of functions as a type, for example a function that takes a
Person and converts it to a
String would be a type
Person => String, then, an
Printable with a single function that converts a
Person to a
String, is just a way to name the type
Person => String, because depending on
that interface means depending on that one function.
In Scala you could depend on the function type itself, or use a
you can think of something akin of an interface, or have a type alias for
Person => String. The last two ways would let you name the dependency, which
might be helpful to express intent.
Similarly, in Haskell you can either depend on the function type
String or define a type alias and name it for expressiveness.
Now, you make your functions depend on these types, and return these types, and that is, in essence, what functional programming is. In pure functional, injecting functionality as functions emerges naturally, and we’ll be able to see more about that when we look into expressions vs statements.
Of course, there is a lot more to it, but in essence FP in OO terms is, dependency injection with segregated interfaces and data/behaviour separation.
In the next chapter, we’ll be more focused on the paradigm specifics, and will be talking about expressions vs statements and functions vs procedures.