What a constant is
A constant is a name whose value is set once and never changes. In Scala you create one with val instead of var:
val ourName = "AlgoCademy"
println(ourName)
AlgoCademy
Reading the value works as with any variable. The difference appears when something tries to change it:
val ourName = "AlgoCademy"
ourName = "Andy"
-- [E052] Type Error ------------------------------------------------------
| ourName = "Andy"
| ^^^^^^^^^^^^^^^^
| Reassignment to val ourName
This is a compile error, so the program never starts. The compiler found the problem before any code ran.
Why limit yourself
A var can do everything a val can and more, so why choose the restricted one? Because the restriction is a promise. When you read a val, you know its value is the same on every line that follows. You don't have to scan the rest of the program for a hidden assignment. In a big program written by many people, that promise makes code far easier to follow, and a colleague who accidentally reassigns an important value gets an immediate compiler error instead of a strange bug.
That is why Scala programmers declare everything with val by default and switch to var only when the value really has to change, such as a counter or a running total.
The exercise step by step
The starting program tries to change a constant:
val pi = 3.14
pi = 5
println(pi)
- Find the error. The compiler points at
pi = 5and saysReassignment to val pi. - Decide what is right. The value of
pishould stay 3.14, so the program is wrong to change it. The declaration is fine as it is. - Delete the assignment line. Leave the declaration and the
printlnline untouched.
Switching to var pi = 3.14 would also compile, but it would print 5 and give up the guarantee that makes pi trustworthy.
The solution in Scala
val pi = 3.14
println(pi)
The blank lines are where the assignment used to be. They make no difference. The program prints:
3.14
Scala infers that pi is a Double from the literal 3.14, so no type annotation is needed.
What val does and does not freeze
val fixes which value the name refers to. It does not always make the value itself unchangeable. A mutable collection stored in a val can still be modified:
import scala.collection.mutable.ArrayBuffer
val buf = ArrayBuffer(1, 2)
buf += 3
println(buf)
ArrayBuffer(1, 2, 3)
The name buf still refers to the same buffer, but the buffer's contents changed. Only an assignment such as buf = ArrayBuffer(9) would be refused. Numbers and strings are immutable themselves, so a val holding one never changes at all.
Common mistakes
- Changing
valtovarto silence the error. This removes the protection. First ask whether the value should change at all. - Thinking a constant must be written in capitals. Scala does not require it. A
valis a constant because of the keyword, whatever its name looks like. - Declaring the same name twice. Writing
val pia second time in the same block is a different error: the name is already defined. - Expecting a runtime failure. The reassignment is caught while compiling, so no output appears before the error.
Key takeaways
valcreates a name that can be assigned only once.- Reassigning it is a compile error:
Reassignment to val. - Use
valby default andvaronly for values that must change. - A
valcan't be re-pointed, but a mutable object it refers to can still be modified.
