LearnAI ToolsCareerPractice BuildsPlayContact
Lesson 416 min read

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")
}
Output

Click Run to see what this code prints.

Prefer val

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 Int
val price = 19.99 // inferred as Double
val name: String // explicit type, no value yet
name = "PrograMinds" // must be assigned before use

Basic 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.

TypeDescriptionExample
Int32-bit whole number42
Long64-bit whole number (suffix L)10000000000L
Double64-bit decimal number3.14
Float32-bit decimal number (suffix f)3.14f
Booleantrue or falsetrue
CharA single character'K'
StringA sequence of characters"Kotlin"
Byte / ShortSmaller whole-number types8-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.")
}
Output

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)
}
Output

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

Avoid These 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.

Next Lesson →

Control Flow