Variables & Data Types
Learn the difference between val and var, Kotlin's built-in types, type inference, string templates, and basic type conversion.
On this page 12 sections
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
varout of Java/JavaScript habit — idiomatic Kotlin prefersvalunless mutation is truly required. - Expecting Java-style implicit numeric widening (e.g.
inttodouble) — 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 tovarif 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
valcreates a read-only reference;varcreates a mutable one — prefervalby 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.