Variables & Data Types
Learn the difference between val and var, Kotlin's built-in types, type inference, string templates, and basic type conversion.
Introduction
Variables are how a program stores and names the data it works with. Kotlin gives you two keywords for declaring them — `val` for values that cannot be reassigned, and `var` for values that can — plus a rich set of built-in types and a type inference system that keeps code concise without sacrificing safety.
This lesson covers `val` and `var`, Kotlin's core data types, type inference, string templates, and how to convert between types explicitly.
val vs var
`val` declares a read-only reference — once assigned, it cannot be reassigned to point at a different value (this is similar to `final` in Java). `var` declares a mutable reference that can be reassigned later. Idiomatic Kotlin strongly favors `val` by default, only reaching for `var` when reassignment is genuinely needed.
fun main() { val name = "Alice" // read-only — cannot be reassigned var score = 90 // mutable — can be reassigned
score = 95 // OK // name = "Bob" // Compile error: val cannot be reassigned
println("$name scored $score")}Click Run to see what this code prints.
Immutable-by-default code is easier to reason about, especially once coroutines and shared state enter the picture. Reach for `var` only when a value genuinely needs to change.
Type Inference
Kotlin is statically typed, but you rarely have to write types out explicitly, because the compiler infers them from the assigned value. You can still write the type explicitly when you want to be clear, or when there is no initial value to infer from.
val age = 30 // inferred as Intval price = 19.99 // inferred as Doubleval name: String // explicit type, no value yetname = "PrograMinds" // must be assigned before useBasic Data Types
Kotlin's built-in types cover whole numbers, decimals, characters, booleans, and text. Unlike Java, every type in Kotlin — even `Int` and `Boolean` — is an object with methods, though the compiler optimizes most of them down to efficient primitives under the hood.
| Type | Description | Example |
|---|---|---|
| Int | 32-bit whole number | 42 |
| Long | 64-bit whole number (suffix L) | 10000000000L |
| Double | 64-bit decimal number | 3.14 |
| Float | 32-bit decimal number (suffix f) | 3.14f |
| Boolean | true or false | true |
| Char | A single character | 'K' |
| String | A sequence of characters | "Kotlin" |
| Byte / Short | Smaller whole-number types | 8-bit / 16-bit |
String Templates
Kotlin lets you embed expressions directly inside string literals using `$`, called string templates. This removes the need for clunky string concatenation with `+` that Java requires.
fun main() { val user = "Priya" val itemCount = 3
println("Hello, $user!") println("You have ${itemCount * 2} points remaining.")}Click Run to see what this code prints.
A bare `$name` works for a simple variable; curly braces (`${expression}`) are required whenever you want to embed a full expression, like a calculation or a method call, inside the string.
Type Conversion
Unlike Java, Kotlin does not perform implicit widening conversions between number types — an `Int` is never silently promoted to a `Long` or `Double`. This is a deliberate safety decision: implicit numeric conversions are a common source of subtle bugs. You must convert explicitly using functions like `.toLong()`, `.toDouble()`, or `.toInt()`.
fun main() { val wholeNumber: Int = 10 val asDouble: Double = wholeNumber.toDouble() // explicit conversion required val asString: String = wholeNumber.toString()
println(asDouble) println(asString)}Click Run to see what this code prints.
A Note on Nullable Types
Every type you've seen so far — `Int`, `String`, `Double`, and the rest — is non-nullable by default, meaning it can never hold `null`. Kotlin has a separate, explicit syntax (`String?`, `Int?`, and so on) for types that are allowed to be null. This lesson deliberately doesn't use nullable types yet — you'll cover them thoroughly, with all the operators for working with them safely, in the dedicated Null Safety lesson.
Common Mistakes
- Defaulting to `var` out of Java/JavaScript habit — idiomatic Kotlin prefers `val` unless mutation is truly required.
- Expecting Java-style implicit numeric widening (e.g. `int` to `double`) — Kotlin requires explicit `.toDouble()` style conversions.
- Using string concatenation with `+` when a string template (`$name`, `${expr}`) is clearer and more idiomatic.
- Forgetting curly braces around expressions in string templates, e.g. writing `"$user.length"` when you meant `"${user.length}"`.
Best Practices
- Start every variable as `val`; only change it to `var` if the compiler or your logic later requires reassignment.
- Let type inference do the work for local variables — only write explicit types when it genuinely improves readability.
- Prefer string templates over concatenation for building strings from variables.
- Be explicit and intentional about numeric type conversions rather than fighting the compiler with unnecessary casts.
Frequently Asked Questions
Not exactly. `val` means the reference cannot be reassigned, but if it points to a mutable object (like a MutableList), the contents of that object can still change. True compile-time constants use the separate `const val` syntax at the top level.
Implicit numeric conversions are a common source of subtle bugs in other languages (silent precision loss, unexpected overflow). Kotlin requires you to convert explicitly so the intent is always visible in the code.
Yes, and it is sometimes good style for function parameters, return types, or when the inferred type would be unclear to a reader.
Key Takeaways
- `val` creates a read-only reference; `var` creates a mutable one — prefer `val` by default.
- Kotlin infers types automatically from initial values, but you can always write them explicitly.
- Core types include Int, Long, Double, Float, Boolean, Char, and String.
- String templates (`$name`, `${expr}`) replace manual string concatenation.
- Kotlin never converts numeric types implicitly — use `.toInt()`, `.toDouble()`, and similar functions explicitly.
Summary
You now know how to declare variables, work with Kotlin's core types, and build strings with templates. Next, you'll learn how to control the flow of your programs with if, when, and loops.