What does `300.toByte()` return, and what general rule governs narrowing conversions like `toByte()`, `toShort()`, and `Long.toInt()`?
answer
- Narrowing truncates, never throws
- 300.toByte() == 44 (low 8 bits)
- Long.toInt() keeps low 32 bits
- Double.toInt() truncates toward zero
- NaN.toInt() == 0
basics
~10 sNarrowing keeps only the low bits and throws nothing. 300.toByte() is 44 because 300 doesn't fit in a byte, so the extra bits are dropped. Always check ranges before narrowing.
solid answer
~40 s`300.toByte()` returns `44`. Narrowing conversions in Kotlin are **lossy and silent**: they truncate to the target type's bit width and never throw. `toByte()` keeps the low 8 bits, `toShort()` the low 16, and `Long.toInt()` the low 32, reinterpreting the bit pattern as a two's-complement signed value. `300` is `0x12C`; the low byte `0x2C` is `44`. Floating-to-integer conversions (`Double.toInt()`) truncate toward zero and discard the fraction, and `Double.NaN.toInt()` yields `0`. Because there's no overflow exception, code that narrows must validate input first or use a range-checked path. If you need a guaranteed-safe widening you call `toLong()`/`toDouble()`; if you need bounds enforcement you check `in Byte.MIN_VALUE..Byte.MAX_VALUE` (after widening) or use libraries that throw on overflow.
code
kotlin · 6 linesprintln(300.toByte()) // 44
println(200.toByte()) // -56 (sign bit set)
println(3.9.toInt()) // 3 (toward zero)
println((-3.9).toInt()) // -3
println(Double.NaN.toInt()) // 0
println(0x1_0000_0001L.toInt()) // 1 (low 32 bits)go deeper
Knows narrowing can lose data and that you should check ranges.
Computes 300.toByte() == 44 from low-bits truncation and knows it never throws.
Explains two's-complement sign reinterpretation, float truncation toward zero, and NaN/infinity edge cases.
Discusses checked-conversion strategies (toIntExact, range guards) and the JVM bytecode rationale behind silent narrowing.
## Narrowing is silent and lossy Kotlin's explicit conversions go both ways: **widening** (`Int.toLong()`) is always safe, but **narrowing** (`Int.toByte()`, `Long.toInt()`, `Double.toInt()`) can lose information and **never throws**. This is a deliberate, performance-oriented choice mirroring the underlying JVM bytecode (`i2b`, `l2i`, `d2i`). ## Integer narrowing = keep the low bits Narrowing an integer keeps only the low N bits of the two's-complement representation: - `toByte()` keeps 8 bits, `toShort()` 16 bits, `toInt()` 32 bits. - The retained bits are reinterpreted as a **signed** value of the target type. ```kotlin println(300.toByte()) // 44 (0x12C -> low byte 0x2C = 44) println(200.toByte()) // -56 (0xC8 -> high bit set -> negative) println(0xFFFFFFFFL.toInt()) // -1 (low 32 bits all ones) ``` ## Floating-point narrowing - `Double.toInt()` / `Float.toInt()` **truncate toward zero** (drop the fraction): `3.9.toInt() == 3`, `(-3.9).toInt() == -3`. - Out-of-range and special values saturate/zero per JVM rules: `Double.NaN.toInt() == 0`, `Double.POSITIVE_INFINITY.toInt() == Int.MAX_VALUE`. - `Double.toLong()` follows the same toward-zero, saturating semantics. ## Safe patterns - **Validate before narrowing**: check `value in Byte.MIN_VALUE..Byte.MAX_VALUE` first. - For Kotlin/JVM, `Math.toIntExact(longValue)` throws on overflow if you want a checked conversion. - Prefer widening conversions when you don't actually need a smaller type. ## Why it matters in interviews The `300.toByte() == 44` trap shows whether a candidate understands two's-complement truncation versus assuming Kotlin protects them. Kotlin removed *implicit* conversions for safety, but the *explicit* narrowing you opt into is exactly as dangerous as Java's casts.
- How would you make a Long-to-Int conversion that throws on overflow instead of truncating?On Kotlin/JVM use `Math.toIntExact(value)`, which throws `ArithmeticException` if the Long is outside Int range, or manually check `value in Int.MIN_VALUE..Int.MAX_VALUE` before calling `toInt()`.
- What is `3.9.toInt()` and why?`3`. Double-to-Int truncates toward zero, discarding the fractional part rather than rounding. Use `Math.round` or `roundToInt()` if you want rounding.
saying these in an interview costs you the question
- Claiming narrowing throws an exception on overflow
- Saying Double.toInt() rounds instead of truncating toward zero
- Assuming 300.toByte() throws or returns 255
- Not knowing narrowing reinterprets as a signed value