skip to content

What are the rules and edge cases for digit underscores and radix prefixes in Kotlin numeric literals? Which forms are illegal and why?

level: middleimportance: nice to knowfreq 25%

answer

  1. underscores = cosmetic, between digits only
  2. no leading/trailing underscore
  3. not adjacent to prefix/suffix/point
  4. 0x hex, 0b binary, no octal
  5. prefix + digits + suffix order

basics

~20 s

Underscores are just visual separators between digits and don't change the value. They can't be at the start, the end, or right next to the 0x/0b prefix. Hex is 0x, binary is 0b, and there is no octal.

solid answer

~40 s

Underscores (`_`) in numeric literals are pure readability aids — the compiler strips them, so `1_000_000` equals `1000000`. The rules: an underscore must sit **between two digits**. It cannot lead (`_100`), trail (`100_`), appear adjacent to the radix prefix (`0x_FF`, `0_xFF`), or border the decimal point/exponent/`L`/`f` markers (`1_.0`, `100_L`). These illegal placements are compile errors. Radix prefixes are `0x`/`0X` for hexadecimal and `0b`/`0B` for binary; decimal needs no prefix; **there is no octal**, so a leading zero like `0123` is just decimal `123` with a redundant zero (and Kotlin disallows leading zeros that look octal in some forms). Underscores combine freely with valid prefixes and suffixes: `0xFF_EC_DE_5E`, `0b1010_0101`, `1_000L` are all valid.

code

kotlin · 6 lines
kotlin
val ok1 = 1_000_000
val ok2 = 0xCAFE_F00DL
val ok3 = 0b1010_0101
// val bad1 = 1000_      // trailing underscore: error
// val bad2 = 0x_FF      // underscore after prefix: error
// val bad3 = _100       // leading underscore: error

go deeper

for a junior

Knows underscores are for readability and that 0x/0b are the prefixes.

for a middle

States the between-digits-only placement rules and that there is no octal.

for a senior

Explains why edge-position underscores are forbidden (tokenization) and composes prefix+underscore+suffix correctly.

for a principal

Connects literal hygiene to code-review standards and lexer/grammar design rationale.

## Underscores are cosmetic Kotlin lets you group digits with `_` for legibility. The compiler removes them; they never affect the value or the type. ```kotlin val m = 1_000_000 // == 1000000 val card = 1234_5678_9012_3456L val hex = 0xFF_EC_DE_5E val bin = 0b1101_0010_0110_1001 ``` ## Placement rules (must be between digits) An underscore is legal **only between two digits**. Illegal placements are compile errors: - Leading: `_1000` - Trailing: `1000_` - Next to the radix prefix: `0_x12`, `0x_12` - Next to the suffix: `1000_L`, `1.0_f` - Next to the decimal point or exponent: `3_.14`, `1_e3`, `1e_3` Valid examples keep the underscore strictly inside the digit run: `0xFF_00`, `1_000.000_1`, `1_000L`. ## Radix prefixes - **Hexadecimal:** `0x` / `0X`, digits `0-9 a-f A-F`. Example: `0xCAFE`. - **Binary:** `0b` / `0B`, digits `0`/`1`. Example: `0b1010`. - **Decimal:** no prefix. - **Octal:** **not supported**. There is no `0o` form, and a C-style leading-zero octal is not a thing in Kotlin. A literal like `0123` is not interpreted as octal. ## Combining with suffixes Prefixes, underscores, and suffixes compose: `0xFFFF_FFFFL` is a hex `Long`, `0b1111_1111u` is an unsigned form (unsigned details belong to the Unsigned Types leaf). The ordering is always: prefix, digit groups (with internal underscores), then suffix. ## Why the restriction Forbidding edge-position underscores keeps tokenization unambiguous — the lexer can always tell where a number starts/ends and where a prefix/suffix attaches, avoiding parsing ambiguity with identifiers or operators.

  • Does `0123` mean octal 83 in Kotlin?
    No. Kotlin has no octal literals; such a leading-zero form is not interpreted as octal (and Kotlin rejects integer literals with redundant leading zeros).
  • Is `1_000_000` a different value from `1000000`?
    No. Underscores are stripped by the compiler; both are the same Int value.

Underscores are like the spaces in a phone number — they help you read it but dialing ignores them, and you can't put a space before the first digit.

saying these in an interview costs you the question

  • Thinking underscores change the numeric value
  • Allowing leading or trailing underscores
  • Believing Kotlin supports octal via leading zero
  • Placing underscores next to 0x/0b or L/f
  • Claiming there is a 0o octal prefix

context