How Interfaces May Eliminate Need For Pattern Matching (sometimes)
Tags: java, beginners
Published: 2021-06-07 14:56:16

---
title: How Interfaces May Eliminate Need For Pattern Matching (sometimes)
published: true
description: Unified interface can replace pattern matching
tags: #java #beginners
//cover_image: https://direct_url_to_image.jpg
---
For about a year, all Java code I'm writing heavily uses functional programming approaches. This provides a lot of benefits, but description of this new style is a topic for [a separate long article](https://dev.to/siy/introduction-to-pragmatic-functional-java-142m). 

Now I'd like to focus on one curious observation: sometimes OO provides a more convenient way to use even purely FP concepts like monads. 

### Short Introduction
Monads is a very convenient [design pattern](https://dev.to/siy/beautiful-world-of-mondas-2cd6), often used to represent [special states](https://dev.to/siy/leveraging-java-type-system-to-represent-special-states-688) of values - potentially missing values (`Maybe`/`Option`) or results of computations which may fail (`Either`/`Result`).

Usually such a monad can be implemented using __Algebraic Data Types__, in particular, __Sum Types__. 

To illustrate the concept, let's imagine that we are implementing Java 8 `Optional` from scratch:

```
public interface Optional<T> {
    <U> Optional<U> map(Function<? super T, U> mapper);
    <U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper);
    ... //other methods
}
```
Now we need two implementations. One will handle the case when we have no value:
```
public class None<T> implements Optional<T> {
    public <U> Optional<U> map(Function<? super T, U> mapper) {
        return new None<>();
    }
    public <U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
        return new None<>();
    }
    ... // other methods
}
```
Another one will handle the case when we have value:
```
public class Some<T> implements Optional<T> {
    private final T value;
    ... //constructor, etc.

    public <U> Optional<U> map(Function<? super T, U> mapper) {
        return new Some<>(mapper.apply(value));
    }

    public <U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
        return mapper.apply(value);
    }
    ... // other methods
}
```
From the practical standpoint, any `Optional<T>` in our application will always be an instance of either `Some<T>` or `None<T>`, unless we add more implementations (sealed classes in Java 16+ solve this issue). In other words, `Optional<T>` is a __sum__ of types `Some<T>` and `None<T>`.

### How About Pattern Matching?
As mentioned above, algebraic data types and monads are concepts which are widely used in FP. In order to handle different cases (for example, `None` and `Some` like shown above), Functional Programming uses _pattern matching_. In practice, it means that the received value is checked for type and then handled accordingly. For example, this is how such a situation is handled in [Rust](https://doc.rust-lang.org/rust-by-example/std/option.html):
```
fn try_division(dividend: i32, divisor: i32) {
    match checked_division(dividend, divisor) {
        None => println!("{} / {} failed!", dividend, divisor),
        Some(quotient) => {
            println!("{} / {} = {}", dividend, divisor, quotient)
        },
    }
}
```
This looks clear, readable and convenient. The problem appears when we need to perform more than one operation on the returned value AND that operations also may return `Optional`. Now we have something like that (let's continue using Rust-like syntax here):

```
match operation1(args...) {
    None => ...,
    Some(value1) => {
        match operation2(args...) {
            None => ...,
            Some(value2) => {
                //do more work
            },
        }
    },
}
```
As you can see, pattern matching works perfectly fine and compiler makes sure that programmer checks all possible cases every time. Needless to say, how good this for the code reliability. But writing and reading such a code is a pain. 

Many FP languages adopted so called `do` syntax to make handling such cases much more concise and readable, but this is another (long) story and source of heated debates. 
Instead, I propose to look at another solution  proposed by OO languages, in particular Java.

### Unified Interface
As you, probably, already noticed, in case of Java both classes implement the same interface. This means that we can just call instance methods without checking for particular type every time:
```
    operation1(args...)
        .flatMap(value1 -> operation2(args...));
```
Adding more operations is just as easy:
```
    operation1(args...)
        .flatMap(value1 -> operation2(args...))
        .flatMap(value2 -> operation3(args...))
        ...
        .flatMap(valueN-1 -> operationN(args...));
```
It does not matter how many operations we need to compose together, code will remain concise, easy to read, write and maintain.

### Conclusion
Of course, the curious observation shown above does not mean that one language/languages/paradigm/etc. is better than the other. Instead, I'm trying to show that we, as programmers, should have our minds open, as the best solution for the problem may come from an unexpected direction.