Kotlin Tips & Tricks (1): there’s no need for ternary operator.

ahmed shaaban
4 min readNov 24, 2020

Reason:-

Kotlin said I don’t have ternary operator, it’s bad for readabilit

  • the idea is that the former expression is more readable since everybody knows what if else does,
  • ? : The Elvis operator is part of many programming languages, e.g. Kotlin but also Groovy or C#. may be unclear if you're not familiar with the syntax already.

Alternative

(1) if statament or when statment

if or when in Kotlin is not a statement but an expression (i.e. it evaluates to a value),

if (condition) exp1 else exp2
if (a) b else c

in the case where you have multiple statements inside the body of an if branch (or the body of else or else if), the last line of the block is the value of that branch

when(a) {
true -> b
false -> c
}

(2) Elvis Presley

the Elvis operator ?: is a binary operator that returns its first operand if that operand is true, and otherwise evaluates and returns its second operand.

x ?: y // return x if x is not null, y otherwise. //Make sure that y is not null or return will be null if both x and y are null
  • the Elvis operator is the ternary operator with its second operand omitted.
  • This can be used to guarantee that an expression won’t return a null value, as you’ll provide a non-nullable value if the provided value is null.
  • The name Elvis Operator comes from the famous American singer Elvis Presley. His hairstyle resembles a Question Mark
  • Instead of the first operand having to result in a boolean, it must result in an object reference. If the resulting object reference is not null, it is returned. Otherwise the value of the second operand (which may be null) is returned.
fun getData(): String {    //return type isn't nullable
val nullableString: String? = getPotentialNull() //This
variable may be null
return nullableString?: "Default Not-Null String"
}

In Kotlin, you could use any expression as second operand, such as a throw Exception expression

return nullStr ?: throw IllegalResponseException("fun return null") 
  • ?: gives you a way to handle the fallback case elgantely even if you have multiple layers of fallback. If so, you can simply chain multiply Elvis operators, like here:
val l = listOf(1, 2, 3)val x = l.firstOrNull { it == 4 } ?: l.firstOrNull { it == 5 } ?: throw IllegalStateException("Ups")

(3) Extension function

use Extension function with Elvis Presley Link and Link

fun T?.or<T>(default: T): T = if (this == null) default else this

fun T?.or<T>(compute: () -> T): T = if (this == null) compute() else this

First one will return provided default value in case object equals null. Second will evaluate expression provided in lambda in the same case.

Usage:

1) e?.getMessage().or("unknown")
2) obj?.lastMessage?.timestamp.or { Date() }
  • code above more readable than if construction inlining

Infix notation

Functions marked with the infix keyword can also be called using the infix notation (omitting the dot and the parentheses for the call). Infix functions must satisfy the following requirements:

infix fun <T> Boolean.then(param: T): T? = if (this) param else null 

Used

println(condition then "yes" ?: "no")

This would make an a ? b : c expression translate to a then b ?: c

infix fun <T> Boolean.then(param: () -> T): T? = if (this) param() else null

used

println(condition then { “yes” } ?: “no”)

more enhancement in code (Link)

data class Ternary<T>(val target: T, val result: Boolean)

create a class to hold your target and result:

data class Ternary<T>(val target: T, val result: Boolean)

create some infix functions to simulate a ternary operation

infix fun <T> Boolean.then(target: T): Ternary<T> {
return Ternary(target, this)
}
infix fun <T> Ternary<T>.or(target: T): T {
return if (this.result) this.target else target
}

Then you will be able to use it like this:

val collection: List<Int> = mutableListOf(1, 2, 3, 4)var exampleOne = collection.isEmpty() then "yes" or "no"
var exampleTwo = (collection.isNotEmpty() && collection.contains(2)) then "yes" or "no"
var exampleThree = collection.contains(1) then "yes" or "no"

part 2

--

--