Blog Infos

Kotlin provides a handy mechanism for representing two pieces of data in a single value: . There is also for representing three pieces of data. I want to provide a simple guideline for when to use a Pair or Triple:

“Don’t ever, for any reason, use a Pair or Triple, for any reason, ever, no matter what, no matter where, or who you are with, or where you are going, or where you’ve been. Ever, for any reason. Whatsoever.”
— Michael Scott
— Matt Robertson

If you are unfamiliar with it, that was a reference to the sitcom The Office. On a more serious note, and are simply lazy data classes. And not the good kind of . To give a simple example, suppose we have a function that returns a size (small, medium, large) and a roast (light, medium, dark). With a Pair our function would look like this:

fun getCoffee(): Pair<Roast, Size>

and would be used like this

val coffee = getCoffee()
print(“A ${coffee.second}, ${coffee.first} roast coffee.")
view raw simple-pair.kt hosted with ❤ by GitHub

Now let’s suppose we also need to allow an option to “leave room for cream.” We’ll represent this as a Boolean. Now we have

fun getCoffee(): Triple<Roast, Size, Boolean>
val coffee = getCoffee()
print("A ${coffee.second}, ${coffee.first} roast coffee with ${if (coffee.third) "" else "no "}room for cream.")

Even an example as simple as this can benefit from a data class. Consider the following.

data class Coffee(
val roast: Roast,
val size: Size,
val leaveRoom: Boolean
fun getCoffee(): Coffee
val coffee = getCoffee()
print("A ${coffee.size}, ${coffee.roast} roast coffee with ${if (coffee.leaveRoom) "" else "no "}room for cream.")

At the cost of a very simple data class, the code is much more readable. And this is a simplified scenario where we already knew what was happening. Imagine running across this in a codebase:

val ounces = coffee.second.ounces - if (coffee.third) 2 else 0

compared to this

val ounces = coffee.size.ounces - if (coffee.leaveRoom) 2 else 0



No results found.

The data class version is immediately readable. The version requires following the surrounding logic and probably digging into the internals of just to figure out what is meant by .

Let’s complicate it a bit further and suppose we have a list of coffee orders, each with an associated name for the order. Using the Pair and Triple method we could represent it as follows:

val orders = mutableListOf<Pair<String, Triple<Roast, Size, Boolean>>>()

And yes, I have actually seen this in real codebases. Let’s consider our data class approach. In addition to the data class above, we’ll also add an data class:

data class Order(
val name: String,
val coffee: Coffee
view raw order-class.kt hosted with ❤ by GitHub

Now we can rewrite the above as follows:

val orders = mutableListOf<Order>()

Consider how these two signatures read.

1. Initialize orders as a mutable list of a pair of a string and a triple of a roast, a size, and a boolean.

2. Initialize orders as a mutable list of orders.

This is what future engineers in the codebase will read when they come across your code. Uncle Bob points out in his book Clean Code, “We are authors. And one thing about authors is that they have readers. Indeed, authors are responsiblefor communicating well with their readers” (p13).

We have an obligation to write clean, readable, maintainable code. Pairs and Triples are anti-patterns that should be avoided in preference for data classes. communicates nothing about meaning or intent. communicates meaning and intent clearly. And if a name doesn’t communicate meaning or intent clearly (perhaps is a bit unclear at first) then data classes allow for KDoc comments to clarify intent, an option that we don’t have with Pair and Triple.

Pairs and Triples are anti-patterns that should be avoided in preference for data classes.

Uncle Bob also notes in Clean Code, “the ratio of time spend reading vs. writing is well over 10:1. We are constantly reading old code as part of the effort to write new code. Because this ratio is so high, we want the reading of code to be easy, even if it makes the writing harder” (p14). Time spent creating data classes is a tiny price to pay for the time that will be saved from not having to decipher intent from Pairs and Triples.

Remember: friends don’t let friends use Pairs.

This article was originally published on on February 23, 2021



It’s one of the common UX across apps to provide swipe to dismiss so…
Hi, today I come to you with a quick tip on how to update…
Automation is a key point of Software Testing once it make possible to reproduce…
Drag and Drop reordering in Recyclerview can be achieved with ItemTouchHelper (checkout implementation reference).…

Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.