Start learning free

LESSON 14 OF 348 · VARIABLES

val vs var in Kotlin: Read-Only or Changeable

Lesson Read the full explanation

Every time you create a name in Kotlin, the language makes you answer one question first: will this value ever change? There are two keywords, one for each answer:

  • val declares a read-only name — it is assigned exactly once and can never be reassigned.
  • var declares a variable — the value is allowed to change later.

This is not just style. When you write val, the compiler guarantees the value never changes — if any line of your program tries to reassign it, the program simply refuses to compile. Whole categories of bugs disappear before the code even runs. That is why Kotlin programmers reach for val by default and only use var when a value genuinely needs to change — a counter, a running total, a position that moves:

val pi = 3.14159      // fixed forever — perfect for val
var lives = 3         // will go down when the player is hit
lives -= 1            // OK — lives was declared with var
println(lives)        // prints 2

Notice there are no type annotations: Kotlin infers that pi is a Double and lives is an Int from the values you assign. And if you declare something with var and never change it, the IDE nudges you the other way: Variable is never modified, so it can be declared using 'val'.


The trap:

Sooner or later you will try to reassign a val. The compiler stops you with this exact error — read it carefully, because it points at the precise line that tried to do the changing:

p1.kt:2:1: error: 'val' cannot be reassigned.
maxLives = 5
^^^^^^^^

The carets underline the exact name that was declared with val, and the two honest ways out are: keep val and stop reassigning, or switch the declaration to var because the value really does need to change. Compound operators hit the same wall — maxLives += 1 fails with the very same 'val' cannot be reassigned. message, because += is just a reassignment in disguise.


Assignment
Follow the Coding Tutorial to build a tiny game setup with one constant and one variable:

  • Declare a read-only maxLives equal to 3 — the rules of the game never change — and print it.
  • Declare a variable score starting at 0, add 10 and then 5 to it with +=, and print the total.

The exact expected output is:

maxLives = 3
score = 15

Hint
Use println("maxLives = $maxLives")-style string templates: $name drops a value into the middle of a string. And if the compiler says 'val' cannot be reassigned., the name you are changing was declared with val — the one value that must change here is score, so declare it with var.


STEP 1 OF 6
    Ctrl + Enter to check

    KOTLIN · VARIABLES

    Val Vs Var in Kotlin, explained

    The question every declaration asks

    Every time you create a name in Kotlin, you choose between two keywords. The choice answers one question: will this value ever change?

    • val declares a read-only name. It is assigned once and can't be reassigned.
    • var declares a variable. Its value may be replaced later.

    This is more than style. With val, the compiler guarantees that no line of the program changes the name, and it refuses to build code that tries. A whole category of bugs, a value changed where nobody expected it, becomes impossible for that name.

    val pi = 3.14159      // never changes: val
    var lives = 3         // goes down when the player is hit: var
    lives -= 1
    println(lives)        // 2
    

    No types are written. Kotlin infers Double for pi and Int for lives from the values. Both keywords work with inference and with explicit types such as val pi: Double = 3.14159.

    Which one to pick

    Kotlin programmers start with val and switch to var only when a value genuinely needs to change: a counter, a running total, a position that moves. If you declare something with var and never reassign it, the IDE suggests changing it to val, because the stricter keyword communicates more.

    The error you will meet

    Sooner or later you will reassign a val. The compiler's message is precise:

    error: 'val' cannot be reassigned.
    maxLives = 5
    ^^^^^^^^
    

    The carets underline the name that was declared with val. There are two honest ways out: keep val and stop reassigning, or change the declaration to var because the value really must change. Compound operators hit the same wall. maxLives += 1 fails with the same message, because += is a reassignment in disguise.

    The exercise, step by step

    The program sets up a tiny game with one value that never changes and one that does. The expected output is:

    maxLives = 3
    score = 15
    
    1. Declare maxLives with val, set to 3. The rules of the game are fixed, so the compiler should enforce that. The type is Int, inferred, so no annotation is needed.
    2. Print it with a string template, println("maxLives = $maxLives"). Read-only means the value can't be changed, not that it can't be read. A name followed by $ inside a string is replaced by its value; a longer expression takes braces, as in ${a + b}.
    3. Declare score with var, starting at 0. A running total has to change, and only var allows that.
    4. Add 10 with +=. score += 10 is shorthand for score = score + 10. The compiler accepts it only because score is a var.
    5. Add 5 more the same way. A var can be updated as many times as you need, and each += reads the current value and stores the new one.
    6. Print the total with println("score = $score"). By now score holds 15 while maxLives is still 3.
    val maxLives = 3
    println("maxLives = $maxLives")
    var score = 0
    score += 10
    score += 5
    println("score = $score")
    

    If score were declared with val, the line score += 10 would stop the build with the reassignment error above.

    Details and common mistakes

    • Reassigning a val. The usual cause is a declaration that should have been var. Ask yourself if the value really has to change before you switch it.
    • Using var everywhere. The program works, but it loses the guarantee. Readers must check every later line to know whether a value can change.
    • The type is fixed either way. A var holding an Int can't later receive a string or a decimal such as 5.5. var allows a new value of the same type, not a new type.
    • val protects the name, not the object. A val that refers to a mutable list can't be pointed at another list, but its contents can still change with add.
    • Order of declaration. A name must be declared before the lines that use it.

    Key takeaways

    • val is read-only after the first assignment; var can be reassigned.
    • The compiler enforces the difference: 'val' cannot be reassigned.
    • Default to val, and use var for counters, totals and anything else that must change.
    • += counts as a reassignment, so it needs var.
    Keep going with KotlinAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free