Scala Variables
Every program needs a way to store data. In Scala, you store data using val and var. These two keywords look similar but behave very differently. Choosing the right one matters for writing safe, predictable programs.
val — Immutable Values
A val stores a value that you set once and never change. Once assigned, it is locked. Attempting to reassign it causes a compiler error.
val country = "India"
val temperature = 36.5
val isRaining = false
country = "Brazil" // Error: Reassignment to val
Think of val like a name badge at a conference. Once printed, it stays the same all day. You cannot cross it out and write a new name mid-conference.
var — Mutable Variables
A var stores a value that you can replace at any time. It is like a whiteboard — you write on it, erase it, and write something new.
var score = 0
println(score) // 0
score = 10
println(score) // 10
score = score + 5
println(score) // 15
val vs var Comparison
┌─────────────────────┬──────────────────────────┬───────────────────────┐
│ Feature │ val │ var │
├─────────────────────┼──────────────────────────┼───────────────────────┤
│ Reassignable? │ No │ Yes │
│ Like a... │ Constant / ink-written │ Pencil-written value │
│ Thread-safe? │ Yes (safer) │ Needs care │
│ Preferred in Scala? │ Yes │ Only when needed │
└─────────────────────┴──────────────────────────┴───────────────────────┘
Why Prefer val?
Scala's community and documentation strongly recommend using val by default. Immutable values are easier to reason about. When a value never changes, you never have to ask "what is this value right now?" — you always know. Programs built on immutable values also work more safely in concurrent (multi-threaded) environments.
Use var only when the data genuinely needs to change over time, like a running total or a counter in a loop.
Type Declarations
Scala infers types automatically, but you can also declare them explicitly:
// Type inferred by Scala
val city = "Tokyo" // Scala sees it is a String
// Type declared explicitly
val city: String = "Tokyo"
// More examples with explicit types
val age: Int = 25
val height: Double = 5.9
val active: Boolean = true
val initial: Char = 'A'
Both styles work. Explicit types are useful for documentation — they make the intent of a variable obvious to anyone reading the code later.
Scala's Core Data Types for Variables
Type │ What it holds │ Example
────────────┼────────────────────────────┼────────────────
Int │ Whole numbers │ val n: Int = 42
Double │ Decimal numbers │ val d: Double = 3.14
Boolean │ true or false │ val b: Boolean = true
String │ Text │ val s: String = "hello"
Char │ Single character │ val c: Char = 'Z'
Long │ Very large whole numbers │ val l: Long = 9999999999L
Float │ Smaller decimal numbers │ val f: Float = 1.5f
Declaring Multiple Values
val firstName = "Ravi"
val lastName = "Kumar"
val fullName = firstName + " " + lastName
println(fullName) // Ravi Kumar
Lazy Values
A lazy val delays computation until the value is actually used. The calculation runs only once — the first time you access it — and the result gets stored for future accesses.
lazy val expensiveResult = {
println("Computing now...")
100 * 200
}
println("Before access")
println(expensiveResult) // "Computing now..." prints here
println(expensiveResult) // uses stored result, no recomputation
Output:
Before access
Computing now...
20000
20000
Use lazy val when the computation is expensive and you might not always need the result. It is like ordering food only when you are actually hungry, rather than ordering everything on the menu upfront.
Variable Naming Rules
Scala follows specific naming conventions:
// VALID names
val myAge = 25
val totalScore = 100
val isLoggedIn = true
val MAX_SIZE = 1000 // constants sometimes use ALL_CAPS
// INVALID names
val 1stPlace = "Gold" // cannot start with a digit
val my-age = 25 // hyphens not allowed
val class = "English" // 'class' is a reserved keyword
By convention, Scala uses camelCase for variable and function names: firstName, userScore, isActive. Class names use PascalCase: UserAccount, OrderItem.
Block Scope
Variables exist only within the block where you define them. A block is any section of code inside curly braces {} — or, in Scala 3, the indented block under a function or expression.
@main def scopeDemo(): Unit =
val outer = "I exist everywhere in this function"
if true then
val inner = "I only exist inside this if block"
println(inner) // works fine
println(outer) // works fine
println(inner) // Error: inner is not in scope here
Think of scope like rooms in a house. Items stored in the bedroom (inner scope) are not available in the living room (outer scope). Items in the living room are accessible from the bedroom.
Updating a var with Compound Operations
var counter = 0
counter += 1 // same as counter = counter + 1
counter += 1
counter += 1
println(counter) // 3
var total = 100
total -= 20 // 80
total *= 2 // 160
total /= 4 // 40
println(total) // 40
Scala supports +=, -=, *=, and /= for compact updates to var values. Note: these operators do not work on val.
Constants as Object Members
For application-wide constants, define val inside an object:
object Config:
val maxRetries = 3
val timeout = 30
val appName = "StudyApp"
@main def run(): Unit =
println(Config.appName) // StudyApp
println(Config.maxRetries) // 3
This pattern keeps constants organized and prevents name collisions across large codebases.
