Big problem in Kotlin not cast dynamically like Apple in swift. How can i do?

Viewed 132

I have a firebase realtime database with this simple scheme:

  • admin
    • price1: 5

if i get database in kotlin:

val result = it.value as MutableMap<String, Any>

When i try to get price1

var price1 = result["price1"] as Long
price1 = price1 + 1

(PRICE1 can be Double or Int) the problem is that if price 1 is 5.5 obviously app killed, but if price 1 is 5, works perfectly.

In swift, i put Double every time and it never gives problems

I find it a bit silly to have to check if it is a double or an int without a comma to be able to do the sum

// im doing this at the moment
var price1 = result["price1"].toString()
if (price1.contains(".")){
     println(price1.toDouble() + 1)
}else{
     println(price1.toInt() + 1)
}

Exist other simple way? Thanks everyone

2 Answers

Kotlin is very strict about types, which is important for type safety.

In your case, you get a value of type Any out of result. It could be anything, not only an Int or a Double. You know that it can only be an Int or a Double, but the compiler doesn't. Many languages allow implicit stuff like type conversion (int to double), type widening (int to long), etc. But these are often sources of nasty errors. See also this discussion Does anybody find Kotlin’s Type Casting disgusting?

Regarding your code: To test a value for its type you use is.

Here is an example of how you could increment by one:

fun increment(value: Any): Any {
  return when (value) {
    is Double -> value + 1.0
    is Int    -> value + 1
    else      -> throw Exception("Value is neither a Double nor an Int")
  }
}

And you would use it like this:

val result: MutableMap<String, Any> = mutableMapOf(
  "price1" to 3,
  "price2" to 3.45
)

var price1: Any = result["price1"]!!   // 3
price1 = increment(price1)
println(price1)   // 4
price1 = increment(price1)
println(price1)   // 5

var price2: Any = result["price2"]!!   // 3.45
price2 = increment(price2)
println(price2)   // 4.45
price2 = increment(price2)
println(price2)   // 5.45

I don't know if Kotlin will ever have union types. Then a declaration like this would be possible:

val result: MutableMap<String, [Int|Double]>   // invalid code

In kotlin all numerable types like Long, Int, Double etc inherit abstract class Number

So your map declaration could be Map<String, Number>. The Number may be easily converted to Double or any other numerable type and then you can work with it as you do in swift:

val map = hashMapOf<String, Number>(
    "1" to 5.5,
    "2" to 5
)

var value1 = requireNotNull(map["1"]).toDouble()
val value2 = requireNotNull(map["2"]).toDouble()
value1++

PS: never use serialization to string as a way to check a type, you can use is operator as @lukas.j suggested

Related