Let’s consider the following case. You need to return 3 different return values from a function. Each
value is associated with information. Say we do authentication
and authorization in one shot. The results
are:
A possible approach is to use enum for that. But enum does not allow us to pass additional information
with each call. To fix that we may return a value object with all fields, but it will add a level
of mess to the callee code.
Yet another apporach is to make the method return a base class or interface and to have an
implementation per return case. This would make code cleaner, but with a cost of instenceof
or visitor pattern impementation.
A nice thing in Kotlin is we are able to use
when expression
to make this checking code read better. In a recent post
I covered when expression benefits.
We may also make sure we check all possible branchs in when expression. For this we only need to
use sealed classes for
return objects hierarchy.
This is example implementation code with sealed class and when expression:
In this example we also need not specify else case for
when expression.
Kotlin compiler is able to prove we listed all types if this sealed class.
Thanks to smart casts
in each when branch we use exactly matched type, so for example, r.message in the first branch
is NotAuthenticated#message and so on.
Generated bytecode
Let’s traditionally take a look into bytecode, that was generated from this code snippet.
Note. I use IntelliJ IDEA 2017.1 EAP with Kotlin 1.0.6 plugin. The generated bytecode
may change with a future version of tools.
Kotlin compiler generated an if-else chain with instanceof checks. First it checks
if the value is AuthResult$NotAuthenticated, next AuthResult$NotAuthorized and finally
AuthResult$Success. In a case something went terribly wrong, a kotlin.NoWhenBranchMatchedException
exception is thrown. And this can be achieved if older version of our snippet is executed with a
newer version of AuthResult class. A full re-compile will fail with error so we were able to
fix the problem easily.
Conclusion
In this post, we looked how when expression is working with sealed classes, which are really nice
to use for cases, where one needs to return several different unrelated values.