Kotlin Type Conversion

Kotlin treats every type as a separate container with its own rules. An Int and a Long hold the same kind of value, yet Kotlin refuses to swap them silently. This strictness prevents hidden bugs. You convert values on purpose, and the code states exactly what happens.

Explicit Conversion

Many languages widen a smaller number into a bigger one without asking. Kotlin demands a clear instruction. The following code fails to compile:

val small: Int = 100
val big: Long = small   // Error: type mismatch

A conversion function fixes the problem:

val small: Int = 100
val big: Long = small.toLong()

The Conversion Functions

Every number type carries a family of conversion functions:

  • toByte(), toShort(), toInt(), toLong()
  • toFloat(), toDouble()
  • toChar() for turning a code into a character
  • toString() for turning any value into text

Cups and Jugs

Imagine four containers of different sizes. A Byte is a tiny cup, a Short is a glass, an Int is a bottle, and a Long is a big jug. Pouring from a small container into a big one always works. Pouring from a big container into a small one spills the extra water.

 Byte      Short       Int          Long
 +--+     +----+     +------+     +--------+
 |  |     |    |     |      |     |        |
 |  |     |    |     |      |     |        |
 +--+     +----+     +------+     +--------+
  8 bits   16 bits    32 bits      64 bits

 small --> big   : safe, nothing lost
 big   --> small : data can spill

Narrowing a number shows the spill clearly:

val number = 300
println(number.toByte())   // 44

A Byte holds values from -128 to 127. The number 300 does not fit, so Kotlin keeps only the bits that fit and the result becomes 44.

Decimals to Whole Numbers

Converting a Double to an Int cuts off the decimal part. Kotlin does not round the value.

println(3.99.toInt())    // 3
println(-3.99.toInt())   // -3

The roundToInt() function rounds to the nearest whole number. It lives in the kotlin.math package.

import kotlin.math.roundToInt

fun main() {
    println(3.99.roundToInt())   // 4
}

Mixed Arithmetic

Math operators accept mixed types for common cases. An Int plus a Double produces a Double. This rule protects the decimal part.

val total = 5 + 2.5    // 7.5 (Double)

Division of two Int values keeps only the whole part. Convert one side to Double to keep the decimals.

println(7 / 2)                // 3
println(7.toDouble() / 2)     // 3.5

Text to Number

Text from a keyboard or a file needs conversion before any math.

val age = "42".toInt()
val price = "19.99".toDouble()
val flag = "true".toBoolean()

Invalid text throws a NumberFormatException. The safe versions return null instead:

val value = "abc".toIntOrNull()    // null
val rate = "x1".toDoubleOrNull()   // null

Number to Text

The toString() function converts any value to text. A string template performs the same job inside a message. Number types accept a base for the conversion:

println(255.toString(2))    // 11111111
println(255.toString(16))   // ff

Characters and Codes

Every character owns a numeric code. The code property reads it, and toChar() rebuilds the character.

println('A'.code)       // 65
println(66.toChar())    // B

A digit character is not the same as its number. The character '7' has the code 55. Use digitToInt() to get the real value:

println('7'.digitToInt())   // 7

Conversion Flow Diagram

 "42" (String)
     | toInt()
     v
   42 (Int) ---- toLong() ----> 42L (Long)
     |
     | toDouble()
     v
  42.0 (Double) -- toInt() --> 42 (Int)
     |
     | toString()
     v
 "42.0" (String)

Good Habits

  • Convert text with the OrNull versions whenever the source is a user or a file.
  • Choose the larger type when you mix values, so nothing spills.
  • Round on purpose with roundToInt() instead of trusting truncation.