Kotlin Language: Variables & Types Refresher
A spaced-repetition refresher on Variables & Types in Kotlin Language, focused on practical implementation details and updates.
Table of contents
Context and Scope
Run date: 2026-03-27. This is a focused refresher on Kotlin “Variables & Types” at the Fundamental level. We’ll cover exactly 11 core concepts: val, var, Type Inference, String, String Templates, Int/Long/Double/Float, Boolean, Char, Any, Unit, and Nothing. Where recent changes matter (notably with the K2 compiler and string interpolation updates in 2025–2026), you’ll get migration notes and links to current docs. (kotlinlang.org)
Conceptual Model & Analogy
Think of your program as a toolbox:
- val is a labeled drawer you can stock once and keep using; the label never moves, but items inside the box it points to can be rearranged. (kotlinlang.org)
- var is a sticky note on a tool; you can peel it off and stick it on a different tool any time. (kotlinlang.org)
- Type inference is your shop assistant who guesses which box you meant from the item you put in—no need to write the label if it’s obvious. (kotlinlang.org)
- Any is “Thing,” the most generic shelf everything fits on. Nothing is a trapdoor with no items at all; once you fall in, execution never comes back. Unit is a receipt with no payload—proof that an action finished. (kotlinlang.org)
Deep Dive
- val (read-only)
- Declare once, never reassign. Suitable for values that shouldn’t change after initialization. Remember: the reference is read-only; the object referenced may still be mutable (for example, a MutableList). Example: val items = mutableListOf(1,2) then items.add(3) is fine; items = otherList is not. (kotlinlang.org)
- var (mutable)
- You can reassign the variable any number of times after its initial value is set. Prefer val by default; use var only when mutation is required. IDEs will suggest converting a local var to val when safe. (kotlinlang.org)
- Type Inference
- Kotlin infers types from initializers and expression bodies, reducing verbosity. Use explicit types for public APIs and when inference reduces clarity. K2 (Kotlin 2.x) made inference and call resolution more consistent; smart casts are also broader in scope. (kotlinlang.org)
- String
- Immutable sequence of characters. Kotlin supports escaped strings (”…”) and raw multiline strings ("""…""") with helpers like trimIndent and trimMargin. Strings are immutable; operations like uppercase() return new Strings. (kotlinlang.org)
- String Templates
- Embed variables ($name) or expressions (${expr}) directly in strings. From Kotlin 2.2, multi-dollar interpolation is Stable, making it easier to include literal $ in single-line or triple-quoted strings without verbose escaping. (kotlinlang.org)
- Int / Long / Double / Float
- Kotlin number types are compiled to JVM primitives where possible for performance; when you need nullability or generics, they’re boxed. There’s no implicit widening; use explicit conversions like toLong() or toDouble(). Integer division truncates; use a floating-point operand to keep fractions. Suffix f or F to force Float; L for Long. (kotlinlang.org)
- Boolean
- Exactly two values: true or false. Logical operators are &&, ||, and !, with short-circuit semantics. Kotlin doesn’t have “truthy/falsy” conversions—only Boolean works in conditions. On the JVM, Booleans map to primitives and are boxed when nullable. (kotlinlang.org)
- Char
- A single Unicode character in single quotes, e.g., ‘A’. Not the same as a one-character String. Use helpers like digitToInt() when converting numeric characters. On JVM, Char is a primitive (char) and boxes when nullable. (kotlinlang.org)
- Any
- Root of the non-nullable type hierarchy; every class ultimately extends Any (top type for non-null). Methods include equals, hashCode, and toString. The absolute top of the type lattice including null is Any? per the spec. Use Any sparingly in APIs—it trades type safety for generality. (kotlinlang.org)
- Unit
- The return type of functions that don’t return a meaningful value; equivalent to Java’s void but is an actual type with a single value. You can omit Unit in function signatures; consider writing it explicitly in APIs where it clarifies intent. (kotlinlang.org)
- Nothing
- The uninhabited type—no values exist. Mark functions that never return (always throw or loop forever). Helps the compiler understand control flow, e.g., with elvis (?:) when the right side throws. Kotlin’s TODO() returns Nothing. (kotlinlang.org)
Baseline Example (quick syntax review)
fun main() {
// val vs var + type inference
val greeting: String = "Hello"
var count = 0 // inferred Int
count += 1 // var is mutable
// numbers
val a = 42 // Int
val b: Long = 3_000_000_000L
val pi: Float = 3.14159f // explicit Float
val precise = 2.71828 // Double by default
// Boolean, Char
val ok: Boolean = true
val letter: Char = 'K'
// String + templates + multiline
val status = "$greeting, count=$count, a=$a, b=$b, π≈$pi, e≈$precise, ok=$ok, letter=$letter"
val banner = """
|Kotlin Refresher
|$status
""".trimMargin()
println(banner)
}
Implementation Patterns
- Prefer val by default; reach for var only when mutation is an explicit requirement. Tools will flag “can be val” opportunities. (jetbrains.com)
- Lean on inference locally; add explicit types at module or API boundaries to anchor intent and avoid surprising changes after refactors. (kotlinlang.org)
- Favor String templates over concatenation for readability. For text with many $ characters (config, JSON, shell), use multi-dollar interpolation (Kotlin 2.2+) or, on older versions, escape with ${’$’}. (kotlinlang.org)
- Mind numeric conversions: there’s no implicit widening; call toLong(), toDouble(), etc. Also note integer division truncates; coerce one operand to Double to retain the fractional part. (kotlinlang.org)
- Use Any for logging/debug sinks or heterogeneous containers, but prefer sealed hierarchies or generics for domain APIs.
- Unit can be omitted; consider writing it explicitly when overloading or to make intent crystal clear in public APIs. (kotlinlang.org)
- Use a small helper that returns Nothing for “fail fast” code paths; it tightens static guarantees in the surrounding code. (kotlinlang.org)
- Style consistency: set Kotlin’s official code style in IDEs or enforce with ktfmt/ktlint; follow domain style guides (e.g., Google’s) when on Android. (kotlinlang.org)
Production-grade Example (types working together)
// Kotlin 2.2+ for multi-dollar interpolation; otherwise replace $$ / $$$ usage as noted below.
private fun fail(reason: String): Nothing = error("Fatal: $reason") // always throws
private fun log(message: String): Unit = println("[LOG] $message") // explicit Unit for clarity
// Accepts anything, uses smart casts (K2 expands smart-cast coverage in more places).
fun debugValue(x: Any) {
when (x) {
is String -> log("String(len=${x.length}): $x")
is Int -> log("Int(doubled=${x * 2})")
is Double -> log("Double(rounded=${"%.2f".format(x)})")
is Char -> log("Char(code=${x.code})")
is Boolean -> log("Boolean(negated=${!x})")
else -> log("Other(type=${x::class.simpleName})")
}
}
// Multi-dollar interpolation example (Stable since 2.2)
// If targeting < 2.2, replace `$$` or `$$$` with literal escapes like ${'$'} as needed.
fun buildJson(name: String): String {
val id = name.ifBlank { fail("Missing name") } // Nothing short-circuits here
val escaped = name.replace("\"", "\\\"")
// $$$ means 3 dollars are required to interpolate; $ and $$ remain literal.
val json = $$$"""
{
"$$schema": "https://example.org/schema",
"name": "$$${escaped}",
"$$price": 12.99,
"active": ${true}
}
""".trimIndent()
return json
}
fun main() {
val price = 9.99 // inferred Double
val stock: Long = 1_000
val flag = true
val ch: Char = '7'
val digit = ch.digitToInt() // Char utility
debugValue(price); debugValue(stock); debugValue(flag); debugValue(ch); debugValue(digit)
println(buildJson("Carrot"))
}
- Notes:
- fail has return type Nothing, so the elvis operator (?:) can use it to end execution in error branches, and the compiler knows subsequent code has a non-null value. (kotlinlang.org)
- Multi-dollar interpolation is Stable in Kotlin 2.2; if you’re on 2.1 or earlier, replace $$ / $$$ prefixes with explicit ${’$’} escapes. (kotlinlang.org)
- K2 expands smart-cast scenarios (e.g., across || and from inline calls), which makes when branches and flow checks more expressive without extra casts. (kotlinlang.org)
Common Pitfalls and Tradeoffs
- val is not deep immutability. A val reference to a mutable object can still mutate; to enforce deep immutability, pick immutable types (e.g., List vs MutableList) or expose read-only views. (kotlinlang.org)
- Integer division truncation. 5/2 == 2; use 5/2.0 or 5.toDouble()/2 to retain fractions. (kotlinlang.org)
- No implicit numeric widening. Explicitly convert; avoid hidden precision loss. (kotlinlang.org)
- Float vs Double literals. 3.14 is Double; use 3.14f for Float. Excess precision in Float literals will be rounded. (kotlinlang.org)
- No truthiness. Only Boolean works in conditions; a List or Int can’t be used as a predicate. (kotlinlang.org)
- Char vs String. ‘A’ is Char, “A” is String; conversions aren’t implicit. Use helpers like digitToInt() for numeric characters. (kotlinlang.org)
- String templates and $. On Kotlin < 2.2, triple-quoted strings can’t use backslash-escaping; you must write ${’$’} to show a literal dollar. On 2.2+, use multi-dollar interpolation for cleaner literals. (kotlinlang.org)
- JVM boxing surprises. Nullable numbers box; don’t use referential equality (===) for numeric wrappers—use structural equality (==). (kotlinlang.org)
Technical Note
Some doc pages still label multi-dollar string interpolation “Experimental,” but the Kotlin 2.2.0 “What’s New” page promotes it to Stable. If you see conflicting labels in site pages or IDE tooltips, trust the release notes for Kotlin ≥ 2.2.0. If you must support older toolchains, keep using the ${’$’} escape approach. (kotlinlang.org)
Sources & Further Reading
- Basic syntax overview (val, var, inference, Unit, templates): https://kotlinlang.org/docs/basic-syntax.html (kotlinlang.org)
- Strings and string templates (multiline, trimMargin/trimIndent, multi-dollar interpolation): https://kotlinlang.org/docs/strings.html (kotlinlang.org)
- What’s new in Kotlin 2.2.0 (multi-dollar interpolation Stable): https://kotlinlang.org/docs/whatsnew22.html (kotlinlang.org)
- What’s new in Kotlin 2.3.0 (latest release notes): https://kotlinlang.org/docs/whatsnew23.html (kotlinlang.org)
- K2 compiler migration guide (inference and smart-cast improvements): https://kotlinlang.org/docs/k2-compiler-migration-guide.html (kotlinlang.org)
- Numbers (JVM primitives, boxing, no implicit widening, integer division): https://kotlinlang.org/docs/numbers.html (kotlinlang.org)
- Booleans: https://kotlinlang.org/docs/booleans.html (kotlinlang.org)
- Characters: https://kotlinlang.org/docs/characters.html (kotlinlang.org)
- Any (stdlib API): https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-any/ (kotlinlang.org)
- Unit (stdlib API): https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-unit/ (kotlinlang.org)
- Nothing (stdlib API): https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-nothing/ (kotlinlang.org)
- Kotlin coding conventions: https://kotlinlang.org/docs/coding-conventions.html (kotlinlang.org)
- Android Kotlin style guide: https://developer.android.com/kotlin/style-guide (developer.android.com)
Check Your Work
Hands-on Exercise
- Write a function loadUserName(id: Int): String? that returns null when id <= 0. In main:
- Declare val name = loadUserName(0) ?: fail(“Invalid id”) using a helper fail(msg: String): Nothing.
- Print a message using a triple-quoted string with templates that includes:
- An Int, a Long (use L), a Float (use f), and a Double.
- A Char converted with digitToInt().
- A Boolean derived from a simple predicate.
- Use multi-dollar interpolation to include a literal $ in the message if your Kotlin is ≥ 2.2; otherwise, escape with ${’$’}.
Brain Teaser
- Given:
- val xs = mutableListOf(1, 2, 3)
- val ys: List
= xs - var n = 1
- val s = “pi ≈ ${3.14159}” Answer:
- Which lines mutate state vs reassign references?
- Why does ys.add(4) fail to compile while xs.add(4) works?
- What is the static type of 3.14159 and how would you force Float?
- How would you embed a literal $ right before pi using Kotlin 2.2+ vs 2.1? Explain using the rules above. (kotlinlang.org)
References
- kotlinlang.org/docs/basic-syntax.html
- kotlinlang.org/docs/strings.html
- kotlinlang.org/docs/whatsnew22.html
- kotlinlang.org/docs/whatsnew23.html
- kotlinlang.org/docs/k2-compiler-migration-guide.html
- kotlinlang.org/docs/numbers.html
- kotlinlang.org/docs/booleans.html
- kotlinlang.org/docs/characters.html
- kotlinlang.org/api/core/kotlin-stdlib/kotlin/-any
- kotlinlang.org/api/core/kotlin-stdlib/kotlin/-unit
- kotlinlang.org/api/core/kotlin-stdlib/kotlin/-nothing
- kotlinlang.org/docs/coding-conventions.html
- developer.android.com/kotlin/style-guide
- kotlinlang.org/docs/whatsnew23.html
- kotlinlang.org/api/core/kotlin-stdlib/kotlin/-unit
- kotlinlang.org/docs/coding-conventions.html
- developer.android.com/kotlin/style-guide
Share
More to explore
Keep exploring
3/12/2026
Kotlin Language: Variables & Types Refresher
A spaced-repetition refresher on Variables & Types in Kotlin Language, focused on practical implementation details and updates.
3/5/2026
Kotlin Language: Variables & Types Refresher
A spaced-repetition refresher on Variables & Types in Kotlin Language, focused on practical implementation details and updates.
3/4/2026
Kotlin Language: Variables & Types Deep Dive (Part 2/2)
A detailed learning-in-public deep dive on Variables & Types in Kotlin Language, covering concept batch 2/2.
Previous
Flutter Layout from the Inside Out: Constraints, Stacks, and the Widgets That Keep You Sane
Next