I have a scenario where two functions return almost the same sealed result classes, with a few exception:
- when the operation is successful, the result class wraps a different type of result. This is not a problem, can be easily solved by using a generic for the sealed class.
- there are specific errors that depend on the type of result. This is where the problem appears, since this specific error has to be handled even when its generic type is incompatible with the declared generic type of the sealed class that the function returns.
Something like this:
sealed class Result<out T>
object GenericError1 : Result<Nothing>()
object GenericError2 : Result<Nothing>()
class Success<T>(val result: T) : Result<T>()
object StringError : Result<String>()
fun returnStringResult() : Result<String> {
return Success("success")
}
fun returnFloatResult() : Result<Float> {
return Success(234324.23432f)
}
// The following functions include a return statements before when so that the when has to be exhaustive
fun messageForStringResult(): String {
return when (val result = returnStringResult()){
is GenericError1 -> {
println("Generic error 1 occurred")
"Generic error 1"
}
is GenericError2 -> {
println("Generic error 2 occurred")
"Generic error 2"
}
is Success -> {
result.result
}
is StringError -> {
println("String-specific error occurred")
"String specific"
}
}
}
fun messageForFloatResult(): String {
return when (val result = returnFloatResult()){
is GenericError1 -> {
println("Generic error 1 occurred")
"Generic error 1"
}
is GenericError2 -> {
println("Generic error 2 occurred")
"Generic error 2"
}
is Success -> {
"Result: ${result.result}"
}
else -> {
"Impossible"
}
}
}
In messageForFloatResult
, it’s necessary to have the else
branch (I want an exhaustive when
), but it would be much better if it wasn’t necessary. Note that it’s impossible for this else
branch to be executed, because StringError
can never be returned from a function that returns Result<Float>
.