1

The following function compiles, but can only used with Doubles:

fun triang(x: Double): Double {
    var m = x - truncate(x)
    if (m < 0) m += 1.0
    return when {
        m < 0.25 -> 4.0 * m
        m < 0.50 -> 2.0 - 4.0 * m
        m < 0.75 -> 2.0 - 4.0 * m
        else -> 4.0 * m - 4.0
    }
}

I want to be able to use that function with Floats as well, so I tried making it into a generic function:

fun <T: Number> triang(x: T): T {
    var m = x.toDouble() - truncate(x.toDouble())
    if (m < 0) m += 1.0
    return when {
        m < 0.25 -> 4.0 * m
        m < 0.50 -> 2.0 - 4.0 * m
        m < 0.75 -> 2.0 - 4.0 * m
        else -> 4.0 * m - 4.0
    } as T // problem here
}

But this doesn't work, because the cast to T causes the warning, "Unchecked cast: Double to T".

How do I correctly write a generic function for both Float and Double?

digory doo
  • 1,978
  • 2
  • 23
  • 37
  • 2
    One way you could do it is via overloading `fun triang(x: Float) = triang(x.toDouble()).toFloat()`. This is exactly what your generic implementation would do. I know this does not answer your question. But it is much more type safe than generic implementation as it will not work for other `Number` types. – Ashwani Mar 21 '20 at 07:46
  • Yes, I might end up doing it like this. But I'm still interested whether it's possible to do it with generics. – digory doo Mar 21 '20 at 07:54
  • No, because there is no way to convert a `Double` back to `T` (neither cast as you tried nor a method); at least without testing all types (like `when(x) { is Double -> ...; is Float -> ...; ... }`) – Alexey Romanov Mar 21 '20 at 08:03
  • You could try `inline fun ...` which would allow the cast, but it would always fail due to boxing (except for `Double`). – Alexey Romanov Mar 21 '20 at 08:06

1 Answers1

0

Kotlin doesn't support casts for numbers like Java, and there is no definite way to convert a number to erased number type. It is much better to overload method for Double and Float.

However, you can suppress this warning, because actually this code will cast the return value to Number first, then it will call <number type>Value from it, but it is not very good, since this function is not designed for integer values and if you call triang(1), it will cause precision loss in result.

Commander Tvis
  • 2,244
  • 2
  • 15
  • 41