GoF Functionalized
Tags: oop, functional
Published: 2024-04-22 16:25:43

As a programmer with an object-oriented Java background, I'm used to thinking in terms like aggregation and inheritance. These and other OO concepts do not have direct counterparts in the functional world. Thus, the conversion, if you require one, might pose a challenge. Today, I'm going to tackle this, by providing you with a simple tool set for performing this mapping.

{% katex %}
  map: OOP \rarr FP
{% endkatex %}

**Why the hell the article is named _GoF_ then?** ~~Heh, just wanted it to sound gravely.~~ Gang of Four patterns are the globally adopted set of the object-oriented best practices. My thought process was the following: _if I can map GoF to FP, I'll be able to map any OO code to FP_. I might be wrong here, but that's a solid foundation to say the least.

**Are you going to explain GoF?** No, I'm not. There are tons of other resources out there, which did this explanation better than I ever could. My favorite one being the [Refactoring Guru](https://refactoring.guru/). In fact, I've honestly stolen pattern usage examples from there to showcase below. On top of that, I will only cover the subset of GoF patterns to highlight the core techniques, which in turn should be enough to convert other patterns. So, to keep up with an article, you should be pretty fluent with the OOP version of GoF. At the beginning of each chapter, I'll link the object-oriented pattern that will be discussed. If you feel uncertain about some of them, take a pause there to rehearse.

**Are you going to begin already?** Yes, yes, right away, my patient reader.

## Construction

To whet our appetite, let's start with an extremely simple pattern and an extremely simple conversion. [The Builder](https://refactoring.guru/design-patterns/builder) one. Any object we create in our applications eventually should be used as an argument to something. Otherwise, it shouldn't be created in the first place (which is in fact true for lazy languages, eager ones create such objects and then just discard them). Thus, we could narrow down the core use case of any Builder to a representation of _default_ and, more importantly, _named_ arguments in an _arbitrary_ order. Languages without all these three features require Builder to emulate them. For example, in Java _default_ property is achieved by using method overloading. However, the other two features have no direct representation, therefore Builder is highly popular in Java code.

```java
void drive(
    CarBuilder.createCar()
        .seats(2)
        .engine(new ElectricEngine())
        .build()
)
```

The same example in Kotlin, which possesses all three features:

```kotlin
fun drive(
    Car(
        seats = 2,
        engine = ElectricEngine(),
    )
)
```

The latter code does not look considerably more concise comparing to the former one, until you remember all the boilerplate required for the first one to compile and work. Anyway, being arguably cleaner, this _is_ a mapping from OOP to FP, since the Kotlin example directly produces an immutable _record_ from the provided _values_, while Java one _mutates_ `CarBuilder` state in order to produce a `Car` object.

## Ornamentation

Guessing from the title, the next pattern we are going to convert is [The Decorator](https://refactoring.guru/design-patterns/decorator). This one contains the OOP bread and butter - inheritance and aggregation. I need to make a side note here: I'm intentionally using the term _aggregation_ instead of the terms _composition_ or _association_. Since the first one could be easily confused with the functional composition and the second one is quite a broad concept even in the object-oriented world. 

The original shortened (and thus non-compilable) Java/OOP version looks like the following:

```java
interface Notifier {
    void send(String message);
}

class BaseDecorator implements Notifier {
    BaseDecorator(Notifier notifier) { ... }

    void send(String message) {
        this.notifier.send(message);
    }
}

class SlackDecorator extends BaseDecorator {
    void send(String message) {
        super.send(message);
        sendSlackMessage(message);
    }
}
```

Since `send` is essentially a function {% katex inline %}String \rarr Unit{% endkatex %}, this hierarchy boils down to a single function:

```kotlin
fun slackNotification(
    baseNotification: (String) -> Unit = {},
): (String) -> Unit = { message ->
    baseNotification(message)
    sendSlackMessage(message)
}
```

And is usable as:

```kotlin
val notifier = slackNotification(
    facebookNotification(
        smsNotification()
    )
)
notifier("Hello World!")
```

As you might have grasped already, the functional tool we used here is named _currying_. Although Kotlin's currying looks less elegant than the one from the truly functional languages, the result is still much more concise than the original approach. 

Reinforcing my point that these two tools can be reduced to one, in OOP there is already a known morphism from inheritance to aggregation. Additionally, it's not only known but is quite popular in a sense that for the most cases it's recommended to choose aggregation between the two. Functional paradigm removes this choice and leaves you with a single option, which can be considered as a form of inheritance, since more _specific_ functions _close over_ arguments passed to a more _abstract_ ones. Rephrasing slightly, returned _closure_ is a _child_ of the _parent_ function. Even more easily, we can convince ourselves that currying is a form of aggregation, since a curried function aggregates data and behavior and then at some point in time performs computations based on those aggregations.    

## Enumeration

From the title, you might have assumed that we're going to discuss [The Iterator](https://refactoring.guru/design-patterns/iterator) now. However, I'm proposing to review the more specific kind of enumeration, the enumeration of the _tree_ leafs. I'm talking about [The Composite](https://refactoring.guru/design-patterns/composite). This one is essentially a tree of data and functional languages are famous for dealing with tree-like data structures. The original pattern has an interface with two children and a method to execute some logic for all off them:

```kotlin
interface Component {
    fun execute()
}

class Leaf(val value: String) : Component {
    override fun execute() = println()
}

class Composite(val components: List<Component>) : Component {
    override fun execute() = components.forEach(Component::execute)
}
```

In OOP code, we see here an inheritance relation. But this inheritance has one distinctive property in comparison to the one we saw above in a Decorator - all children are defined in the same place and thus are known at the compile time. In the object-oriented world, this relation is usually called _sealed_ inheritance. To contrast with an _open_ one in Decorator. The difference is that in Decorator children aren't known beforehand, they might be added later in some library using your library, providing base decorator. In its core, a parent in the sealed inheritance is a _sum_ of all children (i.e. in our example there are only _two_ possible `Component`s - `Leaf` or `Composite`). This is how the same hierarchy is written functionally:

```haskell
data Component a = Leaf a | Composite [Component a]
```

And this is how to execute our functional Composite:

```haskell
execute :: Component String -> IO ()
execute (Leaf x) = putStrLn x
execute (Composite xs) = forM_ xs execute
```

Per my taste, this looks strikingly more powerful than the OOP version (even in a quite concise Kotlin code). But that's debatable. What's not debatable is the fact that we have a one-to-one mapping between _sealed inheritance_ and _sum type_.

Instead of stopping here, I would like to discuss one more notable conversion technique required for the Composite to become fully functional. In the purely OOP version of the pattern, the `components` of the `Composites` are stored in a _mutable private_ field:

```java
private List<Component> components;

void add(Component component) { 
    components.add(component); 
}

void remove(Component component) {
    components.remove(component);
}
```

In the functional approach, a _mutable private state_ is replaced by an _immutable public value_. I'm stressing on _public_ here to underline the difference. In reality, these values are just passed from the outside, thus aren't "owned" by the receiver at all. The same functions in Haskell:

```haskell
add :: (Eq a) => a -> [a] -> [a]
add x xs = if x `elem` xs then xs else xs ++ [x]

remove :: (Eq a) => a -> [a] -> [a]
remove x xs = [y | y <- xs, y /= x]
```

The pattern here is the function {% katex inline %}OldState \rarr NewState{% endkatex %}, i.e. we're accepting some "state" and returning a new one without modifying the received argument. The first reaction of the OOP brain is usually "Wow, this might be cumbersome to use", however:

```haskell
let a = Leaf "Hello"
    b = Leaf "World"
    c = Composite $ add b $ add a []
```

Looks approximately as readable as the object-oriented analog.

## Abstraction

The next conversion is quite obvious, but nevertheless required to be mentioned in order to cover the topic in its entirety. All (or almost all, being too lazy to verify this statement) GoF patterns use _interfaces_ to provide useful abstractions for outside users. In OOP, an interface is a group of method signatures for the single receiver. The same idea in functional languages is represented by _type classes_. The expected and obvious difference being methods replaced by functions. Let's take [The Chain of Responsibility](https://refactoring.guru/design-patterns/chain-of-responsibility) as an example. Its handler can be roughly represented in Haskell as follows:

```haskell
class Handler h where
  type Request h
  type Response h
  canHandle :: h -> Request h -> Bool
  handle :: h -> Request h -> Response h
```

Note that receiver is now passed as a first argument to the `handle` and `canHandle` functions. In fact, similar convention is as well used in some languages featuring object-oriented paradigm (e.g. Python). So, it should be quite familiar. Next, let's define the chain itself:

```haskell
chain :: (Handler h) => [h] -> Request h -> Response h
chain hs r = handle h r
  where
    h = fromJust $ find (`canHandle` r) hs
```

* You can again spot an immutable sequence of handlers as an argument instead of a mutable private collection in an object-oriented version.

To utilize our chain, we would need to create an instance of some handler. Keeping things simple, I'll use the one that works on plain integers:

```haskell
newtype IntHandler = IntHandler Int

instance Handler IntHandler where
  type Request IntHandler = Int
  type Response IntHandler = String
  canHandle (IntHandler i) r = i == r
  handle (IntHandler i) _ = "Hello " ++ show i ++ "!"
```

Finally, the client-side of the pattern:

```haskell
chain [IntHandler 0, IntHandler 1] 0
```

We're passing multiple handlers and then the actual value as a request.

While this looks familiar for an object-oriented brain, functional brains tend to study and adopt much more abstract type classes, commonly borrowed from mathematics. Different sources even separate this kind of abstractions into the so-called _categorical_ programming. In our specific example, we could re-write the whole code above into a single line, using `Foldable`, `Alternative` and `Applicative` classes:

```haskell
chain fs x = asum $ fs <*> pure x
```

Neat, but quite crazy. In case you're not familiar with those three type classes, I'll leave you a homework to understand this ~~functional~~ categorical Chain of Responsibility totaling to thirty-three(!) characters in length. 

## The Ultimate Conversion

By this moment, we've covered all the techniques I had in my pocket. However, I want to quickly revise all of them with a single(!) pattern. The ultimate one. The one so popular that its use cases can easily cover the whole topic of our discussion... Tried guessing? Yes (or no, depending on your guess), it's [The Singleton](https://refactoring.guru/design-patterns/singleton).

The most popular use case of it is to create a single instance of some interface. Let's say we have `Named` interface:

```haskell
class Named n where
  name :: n -> String
```

And then we create the unique noble counting duck, which has the unique noble name:

```haskell
data CountingDuck = CountingDuck

instance Named CountingDuck where
  name _ = "Archibald The Counting Duck"
```

A similar object-oriented use case of a Singleton is to inherit some open abstract class. Continuing with our example, Archibald can serve as a child to an abstract duck with a template for quaking behavior: 

```haskell
quack :: Named n => n -> String
quack duck = name duck ++ " quacking!"
```

A bit different usage of a Singleton is to serve as a marker in the sealed hierarchy:

```haskell
data Duck = Duck String | CountingDuck

quack :: Duck -> String
quack (Duck name) = name ++ "quacking!"
quack CountingDuck = "Noble quacking!"
```

Same as in open hierarchy, Singleton `CountingDuck` always quacks the same way.

An interesting observation here, is an isomorphism between _methods_ and _pattern matching_ branches. In OOP, related functionalities are grouped with a single type, while in FP related types are grouped with a single function. In other words, FP is behavior-centric (i.e. to add a new behavior you need to change a single place and adding behaviors preserves backward-compatibility), while OOP is type-centric (i.e. to add a new type to a hierarchy you need to change a single place and adding new types to a hierarchy preserves backward-compatibility).

```kotlin
object DomesticDuck : Duck {
    fun name() ...
    fun quack() ...
}

object CountingDuck : Duck {
    fun name() ...
    fun quack() ...
}
```

Becomes:

```haskell
data Duck = DomesticDuck | CountingDuck

name DomesticDuck = ...
name CountingDuck = ...

quack DomesticDuck = ...
quack CountingDuck = ...
```

This is the same controversy between a method and a function we saw several times already, but from a slightly different angle.

Lastly, I need to cover the use case, due to which in some circles Singleton is considered an anti-pattern. The global mutable state:

```kotlin
object CountingDuck {
    private var counter = 1

    fun count() {
        counter++
    }
}
// ... later on ...
CountingDuck.count()
```

The direct conversion in Haskell, as expected, completely removes the notion of state:

```haskell
module CountingDuck (count) where

count :: Int -> Int
count = succ

-- ... later on in another module ...
import CountingDuck (count)

CountingDuck.count 1
```

After this, the _anti_ part of the pattern is automatically annihilated. Although, in this example, using the _associated function_ looks pointless, namespacing might improve readability in a scenario of using a Singleton for storing some global _values_:

```kotlin
object ServerSettings {
    val port = 8080
}
// ... later on ...
ServerSettings.port
```

Since this is not really an object-oriented use case, in Haskell it looks almost the same way:

```haskell
module ServerSettings (port) where

port = 8080

-- ... later on in another module ...
import ServerSettings (port)

ServerSettings.port
```

The most notable difference being missing `val` qualifier: indeed, you don't need one, when `val`s are all you have.

## Summary

As a conclusion, here is the proposed mapping from OOP to FP:


```
Sealed Inheritance  ==>  Sum Type
-------------------------------------------------
Open Inheritance    ==>  Currying
-------------------------------------------------
Aggregation         ==>  Currying
-------------------------------------------------
Interface           ==>  Type Class
-------------------------------------------------
a.method()          ==>  function(a)
-------------------------------------------------
state.change()      ==>  change :: State -> State
```

If you think that there are some uncovered object-oriented features, I would be glad to see them in the comments for the discussion.

Hoping that the article was somewhat entertaining and maybe even useful. Wish to meet you again in the future ones!