My excitement has somewhat faded. Both sides are always evaluated, independent of the condition. This is not how an if statement should work. Also, if the two sides don’t have the exact same type, Kotlin is unable to infer the supertype.
open class Mock(val value: Int)
class Mock1(sideEffect: (who: String) -> Unit): Mock(1) {
init {
sideEffect("Mock1")
}
}
class Mock2(sideEffect: (who: String) -> Unit): Mock(2) {
init {
sideEffect("Mock2")
}
}
@Test
fun `should work as expected when left and right are both of different types`() {
val called = mutableListOf<String>()
val sideEffect = { who: String -> called.add(who); Unit }
// Unfortunately, Kotlin can't infer that the supertype Mock satisfies the
// constraints without an explicit cast.
val m1 = Mock1(sideEffect) as Mock given true otherwise Mock2(sideEffect)
assertIs<Mock1>(m1) // condition was true, we get the left value
assertIsNot<Mock2>(m1)
// Unfortunately, Mock2 was created even though it was not used in the end.
assertEquals("Mock1, Mock2", called.joinToString(", "))
called.clear()
val m0 = Mock1(sideEffect) as Mock given false otherwise Mock2(sideEffect)
assertIsNot<Mock1>(m0) // condition was true, we get the right value
assertIs<Mock2>(m0)
// Same here: Both sides are always evaluated.
assertEquals("Mock1, Mock2", called.joinToString(", "))
}