Research

Functional composition

Enhancing RecyclerView with Functional Composition

Stanislav Nedbálek's photo
Stanislav Nedbálek

Author at Avast Engineering

Published

June 30, 2020

Read time

7 Minutes

Functional composition

Written by

Stanislav Nedbálek

Author at Avast Engineering

Published

June 30, 2020

Read time

7 Minutes

Functional composition

    Share this article

    As an Android developer in Kotlin, I often see devs asking why they should use lambdas and what is the benefit of using them. So let me share the concept of functional composition and its benefits with you.
    However before we start with the code, let’s gain some theoretical background. Functional composition, or so called function composition, is a mathematical concept.

    In mathematics, function composition is an operation that takes two functions f and g and produces a function h such that h(x) = g(f(x)). In this operation, the function g is applied to the result of applying the function f to x.

    From Wikipedia: https://en.wikipedia.org/wiki/Function_composition

    Why this is so important you will see later. For now the important part is that we have methods that depend on other methods results.

    Example

    If you are Android developer, you might have seen this:

    This is a very basic implementation of clickListener in RecyclerView. There are a number of issues within this code:

    1.  Holder invokes listener and obtains Model from data field of Adapter – breaks Single Responsibility and Separation of Concerns principles,
    2. Adapter cannot rely on data field consistency, because it’s modifiable by Holder – breaks Encapsulation of Adapter,
    3. Holder relies on use of specific AdapterTight coupling thus no Reusability is possible.

    In the case of RecyclerView‘s Adapter, this is often tolerated. But from my experience, once you learn something bad on a small scale, you will tend to use it on a large scale as well.

    Note: Unfortunately, even the presence of lambda doesn’t make this a functional code! It just anonymizes the instance of the listener, which gives a bit more flexibility and independence, but nothing functional.

    Functional composition to the rescue!

    Let’s adjust the code with the functional composition:

    According to definition h(x) = g(f(x)) we can rename our functions to clickComposite(position) = clickListener(dataProvider(position)). The composition consists of calling clickListener with the result of dataProvider applied on the provided position.

    As a result, we’ve mitigated all the mentioned issues:

    1. Holder is responsible only for propagating position, Adapter for provide data on that position – Single Responsibility is satisfied,
    2. the Separation of Concerns is achieved by moving position to Model mapping out of Holder,
    3. by removing the inner keyword we’ve achieved Encapsulation of Adapter‘s data field and also decoupling both classes, allowing reusability of Holder.

    Note: Don’t be fooled with lambdas. This code uses functional principles, but it’s still fully convertible to interfaces. You don’t need lambdas for this. It will be just much uglier.

    Higher-order function

    If you are an attentive reader you might have noticed, I’ve mixed two terms. Functional composition and function composition.

    By the definition h(x) = g(f(x)) we have made a reactive code that was able to call function g with the result of calling f(x). But we didn’t have the real h(x) that can do composition, we had only lambda with that concrete composition, which is still error prone, boilerplate.

    To address this, we can advance the previous solution to use a Higher-order function. For that purpose, we need some compose operator. So let’s just rewrite the mathematical definition into Kotlin:

    And taste it:


     

    As a result, we have the same benefits from the previous solution, but less boilerplate code. We are able to write Unit tests for the compose function and ensure this code is working correctly. And the readability is also improved (unless you hate math :)).

    Conclusion

    Comparing the last two examples you might have noticed that the first example defines how the object (Holder) will treat the data, while the following two defines what is object’s (Holder) behaviour – what is his FUNCTION. This is the tiny difference that makes functional programming important.

    You should also understand the difference between Functional Composition and Function Composition, how they are achieved, and what they can give you.

    Which one should you choose? Well, it’s up to you. In the end, it’s only about what suits you (and your team) the best.

    PS: During the publishing process of this article, we found some blur in the understanding of what lambda and functional is.
    I would like to dispel some myths. Lambda != functional. Functional code does not require you to use lambdas. You can write functional code with interfaces. You can also write non functional code with lambdas (that was the first example).
    Lambdas describe behaviour, while interfaces define also the identity. You can understand lambdas as method polymorphism – they are matching based on function declaration. They are not meant to be used for modeling complexity, but rather to simplify complexity of a simple thing that you would normally achieve by polymorphism.

    Stanislav Nedbálek

    Author at Avast Engineering

    Follow us for more