What are the parsing edge cases of string templates — adjacent identifiers, $ before non-identifier characters, and nested expressions?
answer
- short form is greedy over [A-Za-z0-9_]
- ${x}1 to stop the name
- underscore is part of the identifier
- $ before space/digit/punct is literal
- nesting works but extract complex logic
basics
~20 sThe short form grabs the longest identifier after $, which can swallow characters you didn't mean. A $ followed by a space or symbol is literal. Braces let you nest other strings and expressions safely.
solid answer
~40 sThe short form `$name` is greedy over identifier characters: `"$foo_bar"` reads the whole `foo_bar` as one name, and `"$x1"` reads `x1`, so when the next character is a letter, digit, or underscore you must use braces to delimit — `"${x}1"` to get the value of `x` then a literal `1`. A `$` followed by a character that can't start an identifier (space, punctuation, another `$`) is treated as a literal dollar. Inside `${ ... }` you can write any expression, including string literals with their own templates (nesting), `when`/`if` expressions, and lambdas. Be careful that the braced body must be a single expression; multi-statement logic should be extracted to a variable or function for readability. Templates are resolved at compile time into concatenation, so there's no runtime ambiguity once parsed.
code
kotlin · 7 linesval x = 5
val foo = 1
println("$x1") // compile error: no variable x1
println("${x}1") // 51
println("$foo_bar") // error: no foo_bar
println("${foo}_bar") // 1_bar
println("50$ off") // 50$ off (literal $ before space)go deeper
Recognizes that touching characters can confuse the short form and braces fix it.
Explains greedy identifier matching, underscores, and when $ is literal.
Understands nesting, single-expression braces, and advocates extracting complex interpolations for readability.
Drives style guidance (brace-when-touching, ${'$'} for dollars, extract complex logic) and reasons about interpolation in code-generation contexts.
## The short form is greedy `$` followed by identifier characters consumes the **longest** run of letters, digits, and underscores: ```kotlin val x = 5 println("$x1") // ERROR: looks for a variable named x1 println("${x}1") // 51 -> value of x, then literal 1 ``` So when a variable is immediately followed by more word characters, you **must** brace it. This is the most common interpolation bug. ## Underscores count as identifier chars ```kotlin val foo = 1 println("$foo_bar") // looks for a variable foo_bar, not foo then _bar println("${foo}_bar") // 1_bar ``` ## $ before a non-identifier char is literal If `$` is followed by something that can't begin an identifier — whitespace, a digit (a name can't start with a digit), punctuation, or `}` — it stays literal: ```kotlin println("100$ total") // 100$ total (space after $) println("$5") // $5 (identifier can't start with a digit) ``` This is convenient but **fragile**: renaming or moving text can suddenly turn a literal `$` into a template. Prefer `${'$'}` when you truly mean a dollar. ## Nesting templates Inside `${ ... }` you can place any expression, including a **string literal that itself contains templates**: ```kotlin val name = "Ada" val verbose = true println("User: ${if (verbose) "name=$name" else name}") // User: name=Ada ``` The inner `"name=$name"` is a full string with its own interpolation, evaluated as the branch result. Nesting works but hurts readability quickly. ## Braced body is one expression The `${ ... }` body must be a single expression (it can be a big `when`/`if`/lambda call). You cannot put statements/`val` declarations directly inside; extract them: ```kotlin // Hard to read: println("${list.filter { it > 0 }.sumOf { it }}") // Better: val positiveSum = list.filter { it > 0 }.sumOf { it } println("$positiveSum") ``` ## Multiline/raw caveat These parsing rules are identical in raw strings; only backslash-escape handling differs (raw strings don't process `\`). So `${x}1` vs `$x1` behaves the same in `""" ... """`. ## Takeaways - Brace whenever a variable touches following word characters. - Don't rely on accidental-literal `$`; use `${'$'}`. - Keep braced expressions simple; extract complex logic.
- Why does "$x1" fail to compile when x is defined but x1 isn't?The short form greedily reads x1 as the identifier; since no such variable exists it's an unresolved reference. Use "${x}1".
- Can you nest a templated string inside ${...}?Yes — the braced body is any expression, including a string literal with its own $/${} templates, e.g. "${if (b) \"n=$n\" else n}".
saying these in an interview costs you the question
- Thinks $x1 prints the value of x followed by 1
- Doesn't know underscores are identifier characters
- Assumes you can write multiple statements inside ${...}
- Relies on accidental literal $ instead of ${'$'}
- Believes nesting templates isn't allowed