Home > Software design >  Kotlin tries to cast a Double to an Int for no reason?
Kotlin tries to cast a Double to an Int for no reason?

Time:06-01

Good day,

I am trying to make this code work:

fun <T: Comparable<T>> getExtreme(data: JSONArray, searchKeyword: String, compareValue: T, define: CompareOp): T {
    val tmpFun: (T, T) -> Boolean = when (define) {
        CompareOp.LESSER -> { a: T, b: T -> a < b }
        CompareOp.GREATER -> { a: T, b: T -> a > b }
    }

    var extremeAmount: T = compareValue

    for (hourlyIndex in 0 until data.length()) {
        val dataSet: JSONObject = data.getJSONObject(hourlyIndex)
        val hourlyUvi: T = dataSet.get(searchKeyword) as T
        Log.d("MATH FUNC", "$hourlyUvi")
        if (tmpFun(hourlyUvi, extremeAmount)) extremeAmount = hourlyUvi
    }
    return extremeAmount
}

But for some reason it always throws this exception:
Exception thrown by Android Studio

I think what the error is, is that each time it reads a whole number it automatically converts it to an Int instead of staying with my specified T. This code works fine and pretty much flawlessly without this line:
if (tmpFun(hourlyUvi, extremeAmount)) extremeAmount = hourlyUvi
If that is the error, how do I enforce my T instead of its own definition, and why is it doing it, or does the error lie anywhere else?

CodePudding user response:

There are several built-in type converters like jsonObj.getDouble(key) or jsonObj.getInt(key) which will appropriately handle conversions when the JSON input string is a numeric type like an integer and you want a different numeric type as an output (e.g. double).

However, using this with a generic output type T is not as straightforward. If you really need to use the generic, you can write a generic JSONObject to T converter. If the JSBONObject is not a numeric type or a string that can be parsed to a numeric type, the getX methods will throw.

Make sure the converter covers all the possible numeric types you want to use, or it will fall to the last case and return the test value. You have to pass in an object of type T for the type checking, even if it is unused.

fun <T> jsonObjToType(o: JSONObject, arg: String, test: T): T {
    return when(test) {
        is Double -> o.getDouble(arg) as T
        is Int -> o.getInt(arg) as T
        is Float -> o.getDouble(arg).toFloat() as T
        is Long -> o.getLong(arg) as T
        else -> test // will never hit this as long 
                     // as all possible T types are covered above
    }
}

and use it in your function

val hourlyUvi: T = jsonObjToNumericType(dataSet, searchKeyword, extremeAmount)
if (tmpFun(hourlyUvi, extremeAmount)) extremeAmount = hourlyUvi

Note: when you use Int or Long types, if there are floating point values in the array they will be truncated to an integer value. In almost all cases it is probably better to just write this function for doubles rather than as a generic of T to appropriately handle all cases.

  • Related