https://kotlinlang.org logo
#k2-early-adopters
Title
# k2-early-adopters
d

Dmitry Stakhov

04/02/2024, 7:56 AM
I am using the mockk in the next code sample:
Copy code
sealed class T {
    object A: T()
    object B: T()
    object C: T()
}

fun foo(param: T) {
    when (param) {
        is A -> { fun1() }
        is B, C -> { fun2() }
    }
}

fun test() {
    foo(mockk<T.C>())
}
the test function throws the
kotlin.NoWhenBranchMatchedException
with Kotlin 2.0.0-Beta5 The fix is easy 1. remove mocking ->
foo(T.C)
2. add the second is explicitly ->
is B, is C -> {}
Is it expected (should we always write is for each branch in the same line) or it should be reported as bug?
k

kirillrakhman

04/02/2024, 8:15 AM
Does this work in K1? Writing
C
in a
when
branch generates an equality check
param == C
whereas
is C
generates
param is C
. It looks somewhat expected that
param == C
returns
false
depending on what
mockk<T.C>()
actually returns, e.g. if it generates some synthetic subclass at runtime.
d

Dmitry Stakhov

04/02/2024, 8:46 AM
Does this work in K1?
Depends on what we consider as "works" XD The behavior on K1:
fun2
is not called (see the updated sample), but there is no runtime error, the function
test
is finished successfully. I guess this is because the mocked C object doesn't equal C (maybe another object reference) that is not expected by K1 compiler during branches check. so there is no
'when' expression must be exhaustive, add necessary 'None' branch or 'else' branch instead
error during the compilation The difference between K1 and K2 is in runtime. K1 ignores the when call, but K2 throws a runtime error.
k

kirillrakhman

04/02/2024, 8:49 AM
I see, thank you. Then, I suspect the difference is in how K2 considers a
when
expression exhaustive. Exhaustive `when`s get an else branch with the
NoWhenBranchMatchedException
.
d

Dmitry Stakhov

04/02/2024, 9:14 AM
Yes, I just checked both K1 and K2 executes fun3 in the next sample.
Copy code
when (param) {
        is A -> { fun1() }
        is B, C -> { fun2() }
        else -> { fun3() }
    }
Anyways I am not sure K2 should throw a runtime error or should ignore the else branch if it's not added like K1
k

kirillrakhman

04/02/2024, 9:15 AM
Feel free to create an issue.
👍 1
d

dmitriy.novozhilov

04/02/2024, 10:49 AM
I'd say this behavior is expected, and the fact that K1 didn't fail on this code is a bug This code
Copy code
when (param) {
    is A -> fun1()
    is B, C -> fun2()
}
is equal to
Copy code
when {
    param is A -> fun1()
    param is B,
    param === C -> fun2()
    else -> throw NoWhenBranchMatchedException()
}
I suspect that mockk creates another instance of type
C
, which breaks the compiler assumption that there is always only one instance of the object
C
, so the
param === C
is false and exception raises
d

Dmitry Stakhov

04/02/2024, 10:59 AM
@dmitriy.novozhilov @kirillrakhman Yes, it makes sense. K2 makes it more explicit, so the behavior is correct. Thank you for troubleshooting.
5 Views