skip to content

How do explicit conversions interact with nullable numeric types and with Char, e.g. converting `Int?` to `Long?` and getting an Int from a Char?

level: seniorimportance: should knowfreq 35%

answer

  1. Nullable: use n?.toLong()
  2. Char.code, not toInt()
  3. Char(code) to build a Char
  4. digitToInt()/digitToChar() for digits
  5. 'A'.code == 65, '7'.digitToInt() == 7

basics

~20 s

For a nullable number you call the conversion with a safe call: n?.toLong(). For a Char, you don't use toInt() anymore — you use the code property to get its numeric code, and Char(code) to go back.

solid answer

~40 s

Conversion functions like `toLong()` are members of the non-null numeric types, so on a nullable receiver you guard with the safe-call operator: `val l: Long? = n?.toLong()`. There is no autoboxing/widening shortcut — the same 'no implicit conversion' rule applies, plus null-safety. For `Char`, the historical `Char.toInt()` / `Int.toChar()` were **deprecated**; current Kotlin (1.5+) uses the `Char.code` property to obtain the UTF-16 code as an `Int`, and the `Char(code: Int)` constructor function to go back. Digit conversions use `Char.digitToInt()` / `Int.digitToChar()`. So `'A'.code == 65`, `Char(65) == 'A'`, `'7'.digitToInt() == 7`. Mixing this with nullability: `someChar?.code` yields `Int?`. The takeaway: Kotlin keeps conversions explicit even across the Char/Int and nullable boundaries, and steers you to intent-revealing APIs (`code` vs `digitToInt`) instead of overloaded `toInt()`.

code

kotlin · 8 lines
kotlin
val n: Int? = "42".toIntOrNull()
val l: Long? = n?.toLong()        // Int? -> Long?

println('A'.code)                 // 65 (UTF-16)
println(Char(66))                 // B
println('7'.digitToInt())         // 7
println(7.digitToChar())          // 7 as a Char
// '7'.toInt() is deprecated; would have been 55

go deeper

for a junior

Knows to use ?.toLong() on nullable and that Char has a numeric code.

for a middle

Uses Char.code / Char(...) and distinguishes code from digit value.

for a senior

Explains the 1.5 deprecation rationale and the digitToInt/digitToChar pair, composing with null-safety.

for a principal

Connects the Char API redesign to Kotlin's explicit-conversion philosophy and API-evolution/deprecation strategy.

## Nullable numerics and conversions Conversion functions (`toLong()`, `toDouble()`, …) are defined on the **non-null** types (`Int`, `Double`, …). Calling them on a nullable value requires a null-safe path — the `?.` safe-call operator: ```kotlin val n: Int? = readLine()?.toIntOrNull() val l: Long? = n?.toLong() // Int? -> Long? val l2: Long = n?.toLong() ?: 0L // with Elvis fallback ``` There is no implicit widening here either; `val l: Long? = n` (with `n: Int?`) is still a type mismatch. ## Char ↔ Int conversions (the modern API) Historically Kotlin had `Char.toInt()` and `Int.toChar()`, but those overloads were **deprecated in Kotlin 1.5** because `toInt()` on a Char was ambiguous (code point vs digit value). The current, intent-revealing APIs: - `Char.code: Int` — the UTF-16 code unit value. `'A'.code == 65`. - `Char(code: Int): Char` — constructor-style function back to a Char. `Char(65) == 'A'`. - `Char.digitToInt(): Int` — numeric value of a digit char. `'7'.digitToInt() == 7` (throws if not a digit; `digitToIntOrNull()` is the safe variant). - `Int.digitToChar(): Char` — inverse: `7.digitToChar() == '7'`. ```kotlin val code: Int = 'A'.code // 65 val ch: Char = Char(66) // 'B' val seven: Int = '7'.digitToInt() // 7 val c7: Char = 7.digitToChar() // '7' ``` ## Why the redesign matters Using `code` vs `digitToInt()` makes the programmer state which conversion they mean, eliminating the classic bug where someone expected `'7'.toInt()` to be `7` but got `55` (the UTF-16 code). This is the 'explicit conversion' philosophy extended to characters. ## Nullable + Char together `someChar?.code` is `Int?`; `someInt?.let { Char(it) }` builds a `Char?`. The safe-call and `let` compose cleanly with these APIs. ## Summary Nullable conversions need `?.`; Char/Int conversions use `code` / `Char(...)` / `digitToInt()` / `digitToChar()`, not `toInt()`/`toChar()`. Same explicit-conversion discipline, clearer intent.

  • Why was `Char.toInt()` deprecated?
    It was ambiguous: people expected the digit value but got the UTF-16 code (e.g. `'7'.toInt()` == 55, not 7). Kotlin 1.5 replaced it with the explicit `code` property and `digitToInt()`.
  • How do you convert an `Int?` to a `Long` with a default of 0?
    `val l: Long = n?.toLong() ?: 0L` — safe call to convert, Elvis operator to supply the fallback when `n` is null.

saying these in an interview costs you the question

  • Using deprecated `Char.toInt()` / `Int.toChar()`
  • Expecting `'7'.code` to be 7 (it's 55)
  • Calling `toLong()` directly on a nullable without `?.`
  • Thinking nullable widening is implicit

context