Let's have this contrived example: ```open class A...
# getting-started
d
Let's have this contrived example:
Copy code
open class A
class B : A()

fun doWork(returnEarly: Boolean): A {
    if (getValue().isError()) {
        if (returnEarly) return A()
    }
    // do some expensive work
    return B()
}

val b = doWork(false)
Is there any way to achieve that
b
has type
B
? The important thing here is the early return from the function, not the actual function signature. I.e. I can imagine that some lambda with clever types is passed instead of the boolean parameter. For the actual use case see https://kotlinlang.slack.com/archives/C5UPMM0A0/p1706037300372059. I hope I have not overdistilled it here :-)
s
I think "some lambda with clever types" would probably end up being pretty much the same as what Raul already suggested when he described making your
Mode
enum into a parameterised type.
d
Hmm, I thought that I could somehow employ the workarounds regarding the lower bound (as mentioned in linked issues) but then I realized that my situation is specific because of that early return. So there's probably no other way other than duplicating the logic. Which is quite unfortunate because the
doWork
function can be much more complicated in reality and basically I would have to duplicate everything which has
returnEarly
as a parameter and an early return anywhere in the body (possibly nested). I wonder whether a plain old exception (caught on the caller side with
returnEarly=true
) wouldn't be simpler in this case 🙂
d
Does
b is B
not work for you here?
Never mind, I just read the original use case. I think the best approach is just to call
getOrThrow
when lenient.
d
I think the best approach is just to call
getOrThrow
when lenient.
You probably to call
getOrThrow
when strict 🙂 That's exactly what I was suggesting in my last sentence and I will probably go this way after all. It's still worth noting that this functional error handling method has its limitations (at least in Kotlin)
d
Well, call getOrThrow() in both cases. If its strict, it might throw, if it is lenient, it won't.
d
It's actually slightly more complex. The strict/lenient decision happens inside the error handler, i.e.
Copy code
callService().getOrElse {
  when (mode) {
    LENIENT -> null
    STRICT -> ... # throw or return Err
  }
}