2

I would like the following kotlin code to work:

val result: Try<Option<String>> = Success(Some("test"))

val test = when {
    result is Success && result.value is Some -> result.value.t // not working
    result is Success && result.value is None -> "Empty result"
    result is Failure -> "Call failed!"
    else -> "no match!"
}

I use the arrow library for the Try and Option monad.

Unfortunately, I can only access the value of the first condition "is Success" and not the second condition "is Some". So, I can only do "result.value", I then get an Option of String.

Am I missing something? This will save me alot of inner ".map" and ".fold" calls.

Update:

I need to cast it first, which is ugly:

result is Success && result.value is Some -> (result.value as Some<String>).t
ielkhalloufi
  • 652
  • 1
  • 10
  • 27

2 Answers2

3

I tried your example in IntelliJ with Kotlin 1.3.21. It shows the reason of the problem: enter image description here

You need to extract the result.value as a variable to make it work. I found the following snippet to solve it


val result: Try<Option<String>> = Success(Some("test"))

val test = when (result) {
    is Success -> when(val value = result.value) {
        is Some -> value.t
        is None -> "None"
    }
    is Failure -> "Call failed!"
    else -> "no match!"
}

I use Kotlin 1.3.x when with declaration syntax.

You may also use Arrow API to get similar result:

val test = result.fold(
    ifSuccess = { it.getOrElse { "None" }},
    ifFailure = { "Call failed!" }
)

Here you do not need to have the else clause in when.

Eugene Petrenko
  • 4,874
  • 27
  • 36
0

You can simplify the pattern matching like this:

val test = result
  .map { it.getOrElse { "Empty result"} }
  .getOrElse { "Call failed!" }

Which is a bit more exhaustive and doesn't require an else alternative

Alternatively, if you don't care about the exception that is thrown you can use toOption on the Try:

val test = result
  .toOption()
  .getOrElse { "No value!!" }

However, that has some obvious loss of information.

I personally would bubble up the Try instance to the consumer of the result collapsing the inner Option with a .map so that the final result is of type Try<String> and let the consumer handle the error.

However, it depends a lot of the actual context of the problem.

pablisco
  • 14,027
  • 4
  • 48
  • 70
  • What if the value were actually the String `"Empty result"`, or `"Call failed!"`, or `"No value!!"`? – gidds Feb 14 '19 at 19:11
  • Yeah, that's bad. However, that's a question about design of the original intention. The question was about casting and control flow... In an ideal world, the en result would be a closed hierarchy (i.e. sealed class) to represent all 3 states and render that on the UI – pablisco Feb 14 '19 at 19:33