Hey guys, I found this really weird compiler behav...
# compiler
r
Hey guys, I found this really weird compiler behavior, is it expected? I have something like this:
Copy code
if (someString == null) {
    methodThatReturnsResultLikeType()
} else if (someString.isBlank()) {
    methodThatAlsoReturnsResultLikeType()
} else {
    yetAnotherMethodThatReturnsSameType()
}.onSuccess { println("SUCCESS!") }
.onFailure { println("FAILURE!") }
Apparently, the
onSuccess
and
onFailure
are only applied to the second if-else expression (the one that actually starts with
else if
) and not to the whole if expression. Such that if
someString
is null, the
onSuccess
/
onFailure
is not called at all. I have to either surround the whole if expression with parenthesis or add a new variable capturing the result. (I'm sorry if this is not the right channel 🙏. Please do LMK)
j
I would be extremely surprised if it were to apply to the outer `if`/`else`, yes.
I think it's a tossup as to whether it's expected that it binds to the inner `if`/`else` or just the final
else
.
I guess it makes sense now that I think about it, because the type of
{ .. }
on the
else
would otherwise be
() -> Result<Whatever>
and there's no
onSuccess
function on that type
Although I'm not sure if you defined
fun <T> (() -> Result<T>).onSuccess(..)
if it would probably take precedence and bind to the final
else
.
🤔 1
So the fact that
onSuccess
is only available on
Result<T>
means that it binds to the inner `if`/`else`
r
Just out of curiosity, if I ask the IDE to switch the if else with a when, this is what it does:
Copy code
when (someString) {
            null -> {
                methodA()
            }
            else -> if (someString.isBlank()) {
                methodB()
            } else {
                methodC()
            }.onSuccess { onSuccess(it) }
                .onFailure { onFailure(it) }
        }
which seems to me like the same thing I see on the bytecode
j
Yep
r
but to me it's very unexpected. I see the if else chain as the "atomic" expression. I don't see the second if-else as its own expression.
j
sure but that's like saying
"hello" + "world".reverse()
should return the whole "hello world" string as reversed
r
I also thought of the {} of the last else being considered a lambda, but I don't think it's the case.
It clearly sees that the else also returns a Result
j
you have to nest additional
{ }
to return a lambda, but the function call might take precedence when creating the expression tree
r
sure but that's like saying
"hello" + "world".reverse()
should return the whole "hello world" string as reversed
is it really? I really don't see it that way, but I guess this is where syntax and how human beings perceive it can be a bit subjective 😅
j
syntactically there is no such thing as
else if
. There's just
else
, and so the second branch of the outer conditional itself contains an expression-producing conditional
r
like the difference to me is that it treats the else if as a standalone expression. To me, if it's part of a larger if chain, the inner branch shouldn't have its own identity. It's just a part of the whole, not a complete expression.
r
anyway, this has been insightful. Thanks guys 🙏
e
yes, it looks confusing. no, it can't change without breaking existing code
thankfully, since the last time this was brought up, there has been an IDE warning added: https://youtrack.jetbrains.com/issue/KTIJ-22055
r
Yap, totally makes sense that it's not easy to change.