https://kotlinlang.org logo
c

Christian Maus

01/12/2020, 6:18 PM
I’m playing around with a GADT example ported from scala and there seems to be be a compiler restriction on kotlin, so that the compiler does not recognize that the resulting type of the expression matches generic type of the case class:
Copy code
sealed class Expression<A>
data class Num(val value: Int) : Expression<Int>()
data class Bool(val value: Boolean) : Expression<Boolean>()
data class Add(val a: Expression<Int>, val b: Expression<Int>) : Expression<Int>()
data class Equals<A>(val first: Expression<A>, val second: Expression<A>) : Expression<Boolean>()

fun <A> eval(e: Expression<A>): A = when (e) {
    is Num -> e.value
    is Bool -> e.value
    is Add -> (eval(e.a) + eval(e.b))
    is Equals<*> -> eval(e.first) == eval(e.second)
} as A

fun main(args: Array<String>) {

    val exp = Equals(
        Equals(
            Num(3),
            Add(
                Num(1),
                Num(2)
            )
        ),
        Bool(true)
    )

    println(eval(exp))
}
Is there a way to get rid of the cast to A?
d

Dominaezzz

01/12/2020, 6:26 PM
Not really.
r

raulraja

01/12/2020, 9:00 PM
We plan to add this as a plugin and send a KEEP for exaustive generic matching. The compiler could potentially calculate the upperbound of the 'when' cases and compare to those of the generic argument for exahustive generic matching that does not require a cast.
👍 2
This also affects all generic ADTs in Arrow.
e

elizarov

01/13/2020, 8:44 AM
The only typesafe way to write it in Kotlin is by explicitly declaring the fact that the
value
of
Expression<A>
has type
A
(otherwise, there’s no way to explain this to compiler, thus the need to use unchecked casts).
Copy code
sealed class Expression<A> {
    abstract val value: A
}
Full code: https://gist.github.com/elizarov/b5400f827616090811ebb348acd4c426
d

dmitriy.novozhilov

01/13/2020, 11:10 AM
44 Views