Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin - Type conversion with overflow exceptions

(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?

like image 972
Matthew Layton Avatar asked Sep 05 '26 03:09

Matthew Layton


2 Answers

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

like image 73
Viktor Penelski Avatar answered Sep 08 '26 14:09

Viktor Penelski


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)
like image 28
Marvin Avatar answered Sep 08 '26 13:09

Marvin