Skip to main content
Donovan LaDuke - Developer

Reactive Programming in Kotlin - The Paradigm


Featured in Android Weekly Issue 595

In honor of what I'm calling "flowvember", this whole month of November will be dedicated to articles discussing functional reactive programming (FRP) and working with Kotlin Flows. That topic is far too large to cover in one go, so to kick things off this article starts by introducing the concepts of functional and reactive programming.

Procedural Programming #

It's important to begin with a quick stop explaining the general alternative to FRP, and that is the imperative or procedural programming paradigm. Procedural programming involves operating step by step through a series of processes to get to a resolution, telling the code how to do the work and not what to do. Here is an example of a block of procedural code. While it is highly readable, it is also very stateful and focuses on outlining the task specifics.

val numbers = (1..10).shuffled().toMutableList()

// Remove Even Numbers
var index = 0
while(index < numbers.count()) {
    if(numbers[index] % 2 == 0) {
        numbers.removeAt(index)
    } else {
        index += 1
    }
}

// Double the values
for(i in numbers.indices) {
    numbers[i] = numbers[i] * 2
}

// Sort the Values Smallest to Largest
for (i in (1 until numbers.count())) {
    val temp = numbers[i]
    var swap = i
    while(swap> 0 && numbers[swap- 1] > temp) {
        numbers[swap] = numbers[swap- 1]
        --swap
    }
    numbers[swap] = temp
}

// Print the Results
for(num in numbers) {
    println(num)
}

Functional Programming #

Functional programming, closely related to declarative programming, is a wide topic, but at its core the important idea is to reduce reliance on state by handling data through transformations in a reproducible manner. This means all functions performed should be idempotent and/or pure, that is they should have the same output for a given input and any side effects should not affect the result. Below is the previous example updated to use a functional style of programming. In the functional style the code declares a series of actions to enact upon the data vs the procedural style which specifies exactly how data will be updated over a series of steps.

val numbers = (1..10).shuffled()

// Remove Even Numbers
val oddNumbers = numbers.filter { it % 2 != 0 }

// Double the values
val doubledNumbers = oddNumbers.map { it * 2 }

// Sort the Values Smallest to Largest
val sortedNumbers = doubledNumbers.sorted()

// Print the Results
sortedNumbers.forEach { println(it) }

Reactive Programming #

In procedural and non-reactive code, the inputs are known at the time of execution. A List is an example of a non-reactive data type. It contains a fixed list of elements that will not change unless acted upon. In a reactive model, the data is accessed as a flowing stream in which new data could arrive at any given time and each element in the stream can be manipulated independently. For this example we will update the code to use a Sequence for simplicity, but in future articles the more powerful Flow construct will be used. The Sequence will emit values as needed, in our case it will do so immediately because we need to sort them, but in other cases it may only emit a subset or specific values. Notice in the code below that instead of printing all values at the end, we react to a new element by printing it, handling each value as it arrives. A sequence is lazy so the .toList() call is needed to cause the sequence to be evaluated and then the onEach will print as expected.

val numbers = (1..10).shuffled().asSequence()

numbers
    // Remove Event Numbers
    .filter { it % 2 != 0 }

    // Double the values
    .map { it * 2 }

    // Sort the Values Samllest to Largest
    .sorted()

    // Print the Results
    .onEach { println(it) }

    // Enumerate the Sequence
    .toList()

Conclusion #

There is no need to do an additional section on combining functional and reactive programming because reactive programming naturally leads to writing functional code, see the above example where each element is acted upon by a function and returns a new value as it arrives. That's all one needs to start working in that paradigm.

As with all software patterns, be wary that this is a new hammer but that doesn't make all problems nails. Functional reactive programming is a useful tool for handling asynchronous streams of data in a readable, maintainable, and testable way but is overkill if you just need to generate a single piece of data or you are not in a constantly changing environment where the program needs to react to constant state changes. The code is available in this gist for those interested in playing with the examples themselves. Until next time, thanks!

Did you find this content helpful?

Please share this post and be sure to subscribe to the RSS feed to be notified of all future articles!

Want to go above and beyond? Help me out by sending me $1 on Ko-fi. It goes a long way in helping run this site and keeping it advertisement free. Thank you in advance!

Buy me a Coffee on Ko-fi