I might've asked this exact question before, so ap...
# stdlib
y
I might've asked this exact question before, so apologies. Why is the internal encoding of
Result
the way that it is? There is a potentially more efficient encoding where you leave failures unboxed, leave most successes unboxed, and only box successes that happen to be throwable. In other words, having the internal encoding be a union of
Throwable | (R - Throwable) | SuccessfulThrowable<R>
j
If I had to guess, it's because exception-based failures should be rare (exceptional, one might say) and are already wildly expensive relative to a little 12 byte box around it.
y
Successful throwables feel even rarer though. Also, exceptions can be much cheaper when their stack traces are disabled. I understand that yeah, at the end of the day, it doesn't matter. It's just interesting that it could be "optimized" further
j
At the cost of some additional instructions at each usage site though, as in the success case you always need to check for
SuccessfulThrowable
as the value if
!is Throwable
y
No that's if the value
is Throwable
, which should be rare (assuming we make SuccessfulThrowable implement Throwable, maybe I should've clarified that)
So 1 extra instance check in the failure case, and 1 extra instance check + a deref in the successful Throwable case
j
Ah, I see. I was assuming it was a simple box.
y
Sorry yeah that was totally my bad. I think I implemented this a while back so I had some of those details assumed but not spelled out. Here's what I'm thinking:
Copy code
private class SuccessThrowable(val value: Throwable): Throwable by error // methods won't be used anyways
fun getOrThrow(): R {
  if (underlying !is Throwable) return underlying as R
  if (underlying is SuccessfulThrowable) return underlying.value as R
  throw underlying 
}
fun <R> success(value: R) = Result<R>(if (value is Throwable) SuccessfulThrowable(value) else value)
fun failure(error: Throwable) = Result<Nothing>(error)
Oops I think I just answered my own question. You need an instance check for every creation of Result. Yeah that's not too nice. Not sure if this was explicitly the reason why, but that's a pretty significant downside if we're counting instruction calls