I would like to reduce the size of an if-elseif-else ladder but can't use just when
because the smartcast doesn't catch the cases I'm dealing with. I'm wondering if I can combine something like a let
or an also
and a when
into a single inline function to solve this.
I've tried using smart casting with is
but it's problematic because I'd have to do a when
within the outer when
to actually get the result I wanted. I ended up doing something similar to one of the responses from this post: Kotlin and idiomatic way to write, 'if not null, else...' based around mutable value by just having a let
block acting on the non-null variable then executing the when
block inside that let
.
Case I'm currently going with:
variable?.let { safeVariable ->
when {
case1 -> doSomething(safeVariable)
case2 -> doSomethingElse(safeVariable)
...
else -> catchAll(safeVariable)
}
return@let
}
Log.e(TAG, "variable was null")
Cases I've considered:
when(variable) {
is Type -> when {
case1 -> doSomething(variable)
case2 -> doSomethingElse(variable)
...
else -> catchAll(variable)
}
else -> Log.e(TAG, "variable was null")
}
if (variable is Type) {
when {
case1 -> doSomething(variable)
case2 -> doSomethingElse(variable)
...
else -> catchAll(variable)
}
} else {
Log.e(TAG, "variable was null")
}
What I'd like to be able to write would look like this:
variable?.alsoWhen { safeVariable ->
case1 -> doSomething(safeVariable)
case2 -> doSomethingElse(safeVariable)
...
else -> catchAll(safeVariable)
} ?: Log.e(TAG, "variable was null")
Is this possible to write in Kotlin with an extension function and if not is there at least an alternative to what I wrote above to make it more compact and readable?
EDIT:
Based on Damon's comment below I did think of a slightly cleaner way to approach this with:
when(true) {
variable?.case1 -> doSomething(variable)
variable?.case2 -> doSomethingElse(variable)
...
variable is String -> catchAll(variable)
else -> Log.e(TAG, "variable was null")
}
It would be nice to get rid of the (true)
next to the when if possible but this is clean enough that I'm pretty happy with the solution.
You can perform the cast inside the argument of the when statement.
E.g.
when (variable as? Type) {
case1 -> ...
case2 -> ...
null -> ...
else -> ...
}
Another example based on comment:
enum class UrlType { TYPE_1, TYPE_2, TYPE_3, NULL }
fun String?.urlType(): UrlType {
return when {
this?.contains("...") == true -> UrlType.TYPE_1
this?.startsWith("...") == true -> UrlType.TYPE_2
this != null -> UrlType.TYPE_3
else -> UrlType.NULL
}
}
when (variable.urlType()) {
UrlType.TYPE_1 -> doSomething()
UrlType.TYPE_2 -> doSomethingElse()
UrlType.TYPE_3 -> ...
UrlType.NULL -> ...
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With