Tag Archives: kotlin

I Know Nothing in Kotlin

When the Greek philosopher Socrates professed that “I know only one thing– that I know nothing,” he wasn’t exactly professing ignorance. It was an ancient formulation of the Dunning-Kruger effect. He had discovered that the more he learned, the wider the expanse of human knowledge seemed and the less that it seemed he knew.

A fool, on the other hand, might believe that they’re “not smart, but genius….and a very stable genius at that,” and that they know “only the best words.”

In this sense, it’s a good thing to know nothing. It’s also true in Kotlin.

During a recent code pairing session, I discovered that in Kotlin, there are numerous developers who have written code in the language for many years. And yet, they still don’t know Nothing.

Our pairing session became a big fuss about Nothing. We were working on some Repository code in our shared Kotlin Multiplatform Mobile (KMM) module of our Meetup for Organizers app. In this code, there was a repeated block at the end of every repository call to handle network, DNS, and timeout errors. We decided it would make sense to refactor this block into a function as we used it so often.

The repeated block in question handled a catch block. It had to re-throw any CancellationExceptions to allow cooperative cancellation of coroutines. Then we had to wrap any other exception and re-throw it as a custom exception type so that we can easily tell iOS a complete list of all types we intend to throw in a @Throws declaration. This allows exception handling and to avoid crashing when our functions are called by Swift code. In essence, this code block always threw an Exception.

The pairing session became quite funny like the Laurel and Hardy “Who’s on First” comedy routine, but you could tell there was Nothing more frustrating, too. It went something like this:

“Why am I getting this red text at the call site?”

“The return type is incorrect because you always throw an exception. You need to return Nothing.”

“I already am returning nothing.”

“No, you’re returning Unit. All Kotlin functions return Unit if you don’t declare a type. You need to return Nothing.”

“I don’t understand. I’m returning nothing from the function.”

“Just trust me. Add it to the return type of the function: Upper case N- lowercase o…”

“I’m so confused.”

It turns out that my colleagues, who had been coding in Kotlin for many years, had never been exposed to Nothing.

Nothing is weird. Nothing is esoteric. But Nothing is quite so useful in these rare cases.

I know Nothing.

“Nothing has no instances. You can use Nothing to represent ‘a value that never exists’: for example, if a function has the return type of Nothing, it means that it never returns (always throws an exception).”

— Kotlin Documentation

The official definition only seems to raise further questions for newcomers to the language.

Why can’t I just return Unit?

Returning Unit would be lying to the compiler and the compiler will miss opportunities to do the right thing. For example, the code in our repository wouldn’t compile because we promised to return a type that wasn’t Unit from each function. Returning Nothing allows our parent function to compile and return the correct type.

What benefits do I get from Nothing?

You do, indeed, get something for Nothing. For one, not using Nothing misses out on correctness benefits like highlighting code as dead and unreachable if we run any code after our function that returns Nothing. Your IDE knows quickly that it stops at Nothing to show the right warnings. If we wrote the same code in Java, there would be no warnings.

Generics are also an area that is good for Nothing. If you want to create an object inside a templated sealed class that doesn’t have any type, its type is Nothing. Any other solution won’t compile.

// credit to Allan Caine @ Kotlin Academy
sealed class LinkedList<out T>  {

    data class Node<T>(val payload: T, var next: LinkedList<T> = EmptyList) : LinkedList<T>()

    object EmptyList : LinkedList<Nothing>() 
}

Nothing doesn’t only apply to functions where you always throw. Nothing is valuable for early returns, such as replicating the Swift guard() function in Kotlin:

// credit to Zac Sweers
inline infix fun <T> T?.guard(block: () -> Nothing): T {
  return this ?: block()
}

fun sweetNothings(input: String?) {
  val value = input guard {
    show("input is null!")
    return
  }
}

Why doesn’t Kotlin just determine automatically that my function returns Nothing and handle this for me?

As to my third and final question, automatically determining that a function returns Nothing would cause a number of problems. Both the compiler and IDE checks would take longer to run as they need to test every branch. Automated type inference would produce some surprising types that could lead to later bugs.

Finally, we should tell the creators of Kotlin, “Thanks for Nothing!”

If you enjoyed my blog post, you ain’t seen Nothing yet. Subscribe to my RSS and keep reading!

Remember, Remember, Jetpack Compose

During the first Kotlinconf in 2017, I asked Google for some kind of declarative user interface (UI) framework for Android. Specifically, I approached Stephanie Cuthbertson and Yigit Boyar at that San Francisco conference. I told them I liked the idea of Anko Layouts, the defunct framework developed by the Kotlin team at Jetbrains, but it really needed a solution with first party support and first class execution.

I’m sure many Android developers asked for something similar, just as many had asked Google for first-party Kotlin support in Android before they announced it at Google I/O 2017.

Today, Jetpack Compose not only delivers on my original request. It goes far above and beyond it. It solves the fragmentation problem of many Android OS versions showing UI widgets with different appearances. It fixed the issues of writing complex Adapters with so many kinds of rows for RecyclerViews. It even promotes stateless, functional UI and unidirectional data flow.

We’ve been working full-time in Jetpack Compose for almost six months now on our new Meetup for Organizers app and we love it.

Why I can’t remember()

However, I would like to focus in this blog on one particular, easily misused part of Jetpack Compose… the remember() function.

Here’s a TL;DR (too long; didn’t read) summary of what I’m about to write about the remember() function:

  1. remember() as little as possible. Just keep the exact pieces of data you really care about in Composable functions. The rest can be passed into your function.
  2. If you don’t want to lose state on rotation, use rememberSaveable(). Write a Saver only if necessary. @Parcelize can help.
  3. If the data is so large it could grow to hit a TransactionTooLargeException, you should persist that data and rememberSaveable() the keys instead.
  4. If you care about not losing data when the user leaves and returns to that screen, you should persist the data from the ViewModel and restore it when needed.

Ever since the beginning of Android development, memory and persistence has easily been one of the hardest challenges. Over the years, so many developers have had their apps break, crash, or forget data by screen rotation or by memory eviction. While Jetpack Compose is amazing, it doesn’t really eliminate these challenges.

One of the first tools Android developers learn when they start to explore Compose is the remember() function. And it’s likely one of the first they should forget. remember() has value when saving state in some notable circumstances, but it’s not great if your state is user input. I’ve seen very senior developers make basic errors when it comes to using remember().

remember() exists to save state in Composable functions between recompositions. However, it has many issues.

First of all, remember() doesn’t handle some configuration changes like rotation. If you rotate the screen, all remembered data on the screen is lost. There’s an easy fix for this called out immediately in the Compose docs. You can instead use rememberSaveable().

Our saving grace

Now, you’re probably thinking this whole blog is advocating that you should simply use rememberSaveable() and all problems are resolved, but that’s not my conclusion at all. Once you start using that new function, your solution can now cause three new problems.

If your state is complex, like a data class, sealed class, or class, then you now have to write a Saver for that class to explain how to bundle it. The quickest option is the @Parcelize annotation, but that might not be available in some circumstances.

Then there’s the TransactionTooLarge exception to contend with. Anyone who’s been writing Android apps for a long time knows that if you put too much into a Bundle, then save it to instance state to restore, you will run into this common crash. Anything you save with rememberSaveable() should be small and the entire Bundle should be small in aggregate.

Third, if your Composable function goes off of the screen, even for a moment, everything you remembered with rememberSaveable is lost. This is easy to encounter, for example, if you use Jetpack Compose Navigation and load a new route for a sub-screen. Let’s say your settings page needs a child page. When you return, your composable forgets everything you thought you remembered.

A pretty state of affairs

The solution to the last two problems is persistence. Ideally, you should be saving to your ViewModel or to a database, such as Room or SqlDelight (for Kotlin multi-platform projects). The only values which belong in rememberSaveable() when the state is very complicated are keys to query your database to retrieve the persisted data.

When you think about using the remember() function, just remember…

Do you care if data is lost on rotation? You shouldn’t use remember().

Is the data too large to store in an instance state? If so, you should be persisting data instead of simply using rememberSaveable().

Never forget. While Jetpack Compose is amazing and it makes our jobs as developers so much better, it doesn’t absolve us of concerns about persisting state.