Kotlin — Using When

J Banks
Software Tidbits
Published in
4 min readJun 13, 2020

In this software tidbit, we use Kotlin’s when keyword to simplify matching of nucleotide codes to ranges, single values, and Kotlin types.

What is When?

A nice offering of Kotlin is the when keyword, which replaces the switch operator found in other languages.

The when keyword checks the target argument against branch conditions until it locates a match. Interesting enough, the when keyword can be used as an expression or as a statement.

When being used as an an expression, the when becomes the value of the satisfied branch. In this case, the else branch is required unless all possible cases are covered with branching conditions. Not using an else branch is possible when the compiler can guarantee the when always returns a value. Checkout using when with Kotlin’s sealed or enum classes to further enhance its usage.

If using the when keyword as a statement, the result is the value of the last expression in the block.

Example Usage

Below is a scenario where a String value is returned back to the caller when the supplied code(a String type) matches specific value. Here, the when keyword is being used as part of an expression.

fun nucleotideName(code: String?): String = when (code) {
null -> throw IllegalArgumentException("code supplied is null")
"T" -> "thymine"
"A" -> "adenine"
"C" -> "cytosine"
"G" -> "guanine"
else -> "unknown code supplied: $code"
}

Notice how the input code is allowed to be null in the example above. In Kotlin, this input can be protected by removing the ‘?’, negates the need for a null check in the when expression.

fun nucleotideNameCodeNotNull(code: String): String = when (code) {
"T" -> "thymine"
"A" -> "adenine"
"C" -> "cytosine"
"G" -> "guanine"
else -> "unknown code supplied: $code"
}

Nice, but what if we wanted to match a branch based on a range instead of a single letter? Let’s see how Kotlin handles this with another when expression handling pH value ranges.

Here, the input is an Int value and if the value is found within a range, the proper pH type is returned as a String.

fun phType(value: Int?) : String = when (value) {
null -> throw IllegalArgumentException("value supplied is null")
in 0..6 -> "acidic"
in 7..7 -> "neutral"
in 8..14 -> "alkaline"
else -> "out of range detected: $value"
}

A single String value is still returned, however the value passed in can be checked for a match within a range of Int values.

Below is an example usage of when, used as a statement within a function. Notice how the when keyword is no longer on the right side of an equals sign!

fun phTypeWhenStatement(value: Int?) {
when (value) {
null -> throw IllegalArgumentException("value supplied is null")
in 0..6 -> println("acidic")
in 7..7 -> println("neutral")
in 8..14 -> println("alkaline")
}
}

In this case, the pH types are simply printed with no return String. Also, there is no requirement for an else statement as none of the branches need to match. However, for sake of defensive coding, one should be included for announcing an “out of range” value.

Using With and Is

The final example shows how flexible this becomes when having to support more complicated use cases. The logic has to support pH value inputs of varying types: String, Int, Long, Float, and Double. When a String is supplied, it is recommended to put checks around the provided value as it could be anything from an actual number to be converted or a non-convertible value (e.g. “foobar123”).

Instead of making the phType() function handle this complexity, a new function is created called normalizePhValueType(), which returns the String value representing the pH type and accepts any input type (using Kotlin’s Any type) with the job of normalizing to an Int value.

fun normalizePhValueType(value: Any?): String? = when (value) {

null -> throw IllegalArgumentException("value supplied is null
or not able to be normalized to number")

is String -> {
val stringToValue: Any? =
value.toDoubleOrNull()
?: value.toFloatOrNull()
?: value.toIntOrNull()
normalizePhValueType(stringToValue)
}
is Int -> phType(value)
is Float -> phType(value.roundToInt())
is Double -> phType(value.roundToInt())
is Long -> phType(value.toInt())
else -> throw java.lang.IllegalArgumentException("pH value's
type can't be converted")
}

The normalized value is used as the input to the phType(value:Int?) function, where the result is returned to the caller.

Notice how when the String type is handled, recursion is used to invoke the same function currently executing. This, in turn, will handle the values for null (or garbage), Int, Float, Double, or Long.

There you have it, uses of when with Kotlin. I hope you enjoyed this software tidbit. Checkout the shared source and don’t forget to like this if you find it useful in your Kotlin development!

Until next time …

References

Immune system responses and pH levels

Nucleotides

--

--