There is an ongoing discussion about the difference between object-oriented programming (OOP) and functional programming (FP). Let's talk about similarities instead.
In the previous post, we talked about "atoms": objects and functions. In this post let's talk about bigger building blocks.
What is a design pattern?
Alexander et al. define a pattern as follows:
A design pattern is a three-part rule, which expresses a relation between a certain context, a problem, and a solution. The pattern is, in short, at the same time a thing, ..., and the rule which tells us how to create that thing, and when we must create it.
-- A Pattern Language: Towns, Buildings, Construction, 1977
They become popular after the book "Design Patterns: Elements of Reusable Object-Oriented Software" by Erich Gamma et al. (sometimes referred as Gang of Four - GoF).
There was prior work in this area, for example:
- SmallTalk introduced a lot of design patterns (including famous MVC)
- Kent Beck talked about patterns in 1987, etc.
If we follow Alexander's definition there is nothing OOP specific (their book is about architecture anyway). For example, algorithms and data structures could be thought as patterns - if you need a list with O(1) access you can use arrays (or vectors), but the restriction is...
Currently when people say "design pattern" they most likely refer to GoF or similar OOP patterns.
Some people criticize the idea of design patterns.
What is a pattern in FP?
There is no same concept of "design pattern" in FP in sense of "bigger building blocks", the closest thing I can think of is categories from category theory. It is not bigger scale because function itself can be thought as a category.
I don't want to deep dive in category theory so I will give simplified picture, so we can do a simple comparison.
Category theory is a toolset for describing the general abstract structures in mathematics.
As opposed to set theory, category theory focuses not on elements x,y,⋯ – called objects – but on the relations between these objects...
-- ncatlab.org
You should have approximate understanding of what is category after this definition, not precise. We don't need precise because we will compare one pattern to the function as an example and stop there.
Typical critics of categories (in programming) is that it is hard to understand. By hard to understand I mean that they are very abstract and it is hard to relate to it.
A monad is a monoid in the category of endofunctors, what's the problem?
-- Joke from A Brief, Incomplete, and Mostly Wrong History of Programming Languages
Other people may say that categories are easier to understand than design patterns because they are precisely defined (this is math). I look at it from this PoV: I was able to explain what pattern is (I hope), but for category theory, I gave only mare shadow of an explanation.
Strategy vs function
There is a big article which compares design patterns to categories. You can read it if you want more details. We will talk about one approachable example.
Strategy pattern vs function (functor)
The strategy pattern ... is a behavioral software design pattern that enables selecting an algorithm at runtime. Instead of implementing a single algorithm directly, code receives run-time instructions as to which in a family of algorithms to use
In OOP this pattern would be implemented as different objects (or classes) with the same method:
// a11, a2
class AlphabeticCompare {
compare(x, y) {
/* ... */
}
}
// a2, a11
class NaturalCompare {
compare(x, y) {
/* ... */
}
}
In FP there is no need to construct objects for this, instead, we can pass functions as values:
// a11, a2
const alphabeticCompare = (x, y) => {
/* ... */
};
// a2, a11
const naturalCompare = (x, y) => {
/* ... */
};
Take away
My idea is to show that there are some core ideas which are same-ish in both paradigms.
Top comments (5)
Thanks for the article, didn't know the GH link!
I would take those with some reservation though. For example, randomly looking, the advice to relate
Builder
withrecord syntax, smart constructor
is very odd.The benefit of
Builder
is that it protects from building incomplete/invalid instances. Using record syntax, with dummy default data, doesn't help that at all.They get the OO
Builder
wrong too, with using default fields. The builder should explicitly warn on required but uninitialized fields (apart from other checks).Btw, for Java I recommend
AutoValue
withBuilder
, see github.com/google/auto/blob/master....I guess you can open issue or PR in GH repository.
True. I pass on the opportunity though :)
Regarding design patterns, please take some time to read following presentation and articles:
Especially the first one is a response to "Design Patterns" book by Gang of Four.
And IMO it's straight to the point. One interesting conclusion might be that OOP languages sometimes create problems that have to be solved by "patterns". But other languages (dynamic, functional) may contain mechanisms to easily solve the same problems, without patterns.
Second and third are somewhat interesting, but very strongly opinionated. Be warned! :)
Well put.
P.S. Things really get interesting when you combine OOP and FP (which, of course, means you're not fully following either?)