(123L).toInt() produces 123 but Long.MAX_VALUE.toInt() produces -1. Clearly this is not correct. Without having to write a lot of boilerplate code, is there a way to get Kotlin to throw an exception when a value is out of range/bounds for the target type?
TL;DR you can make a custom extension function that checks if the value is between Int.MIN_VALUE and Int.MAX_VALUE
fun Long.toIntThrowing() : Int {
if (this < Int.MIN_VALUE || this > Int.MAX_VALUE) {
throw RuntimeException()
}
return this.toInt()
}
The "weird" behavior you are observing is happening, because in Kotlin, Long is represented as a 64 bit signed integer, while Int is represented as a 32 bit signed integer.
While 123L is easily representable by a 32 bit integer, Long.MAX_VALUE will overflow the Integer (almost) twice, resulting in the behavior you are observing.
I believe the example below will illustrate it better:
println((2147483647L).toInt()) // the max 32 bit signed int
println((2147483648L).toInt()) // 1 more overflows it to the min (negative) 32 bit signed int
println((2147483649L).toInt()) // 2 more...
println((Long.MAX_VALUE - 1).toInt())
println((Long.MAX_VALUE).toInt())
results in :
2147483647
-2147483648
-2147483647
-2
-1
From: https://discuss.kotlinlang.org/t/checked-and-unsigned-integer-operations/529/2
Exceptions on arithmetic overflow: this will likely make arithmetics significantly slower, and we don’t see how to avoid it without changes to the JVM, nor are we ready to accept the slowdown
If you are running on the JVM you may use Math.toIntExact:
Returns the value of the long argument; throwing an exception if the value overflows an int.
There doesn't seem to be a pure Kotlin way, but at least you can nicely wrap it:
fun Long.toIntExact() = Math.toIntExact(this)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With