Add ternery operator

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(", "))
}
1 Like

Of course you need lambdas if you want to defer evaluation:

class Given<T>(val left: () -> T, val condition: Boolean)

infix fun <T> (() -> T).given(condition: Boolean) = Given(this, condition)
infix fun <T> Given.otherwise(right: () -> T) = if (condition) left() else right()

fun main() {
    println({4.2f} given true otherwise {8.5f})
    println({4.2f} given false otherwise {8.5f})
}
1 Like

I know, but that means that the call site now requires curly braces, but I could have written clarifying curly braces for the original if statement in the first place. So, the entire Given construct does not help anything. Bah.