Classes and constructors
A class is a blueprint for objects that bundle data with the methods that work on it. In Scala the constructor is not a separate method: the parameters go straight after the class name — class Account(owner: String, balance: Double) — and that line is the primary constructor. Every statement in the class body runs when an object is created. You create an instance by calling the class like a function, Account("Asha", 100); the new keyword still works but Scala 3 no longer needs it.
class Account(val owner: String, var balance: Double):
println(s"opening account for $owner")
def deposit(amount: Double): Unit =
balance += amount
def summary: String = f"$owner%s has $balance%.2f"
@main def run(): Unit =
val a = Account("Asha", 100)
a.deposit(25.5)
println(a.summary)
println(a.owner)
a.balance = 0
println(a.balance)opening account for Asha
Asha has 125.50
Asha
0.0The println in the class body ran during construction. summary has no parentheses: a method that only reads state is conventionally declared and called without (), so it looks like a field.
Add a method withdraw(amount: Double): Boolean that only takes money out when the balance is high enough and returns whether it did.
val, var or nothing: what the parameter becomes
| Parameter | Readable from outside? | Reassignable? | Use it for |
|---|---|---|---|
class A(val x: Int) | Yes — a public getter | No | Data callers should see |
class A(var x: Int) | Yes — getter and setter | Yes | Rarely; prefer methods that change state deliberately |
class A(x: Int) | No — private to the class | No | Inputs used only inside the class |
Constructor parameter without val is not a field
class User(name: String, age: Int)
@main def run(): Unit =
val u = User("Asha", 30)
println(u.name)-- [E173] Reference Error: Main.scala:5:12
5 | println(u.name)
| ^^^^^^
|value name cannot be accessed as a member of (u : User) from the top-level definitions in package <empty>.
| private value name can only be accessed from class User.
1 error found
Compilation failedA plain constructor parameter is visible everywhere inside the class, but Scala treats it as private. Nothing outside User can read it, so u.name is refused. Java and Kotlin developers hit this constantly.
Put val in front of each parameter that should be public. (A case class, Module 05, makes every parameter a val for you.)
class User(val name: String, val age: Int)
@main def run(): Unit =
val u = User("Asha", 30)
println(u.name)Default arguments from Module 03 work on constructors too, which is why Scala rarely needs extra constructors. When you do, an auxiliary constructor is written def this(...) and must start by calling another constructor of the same class.
class Server(val host: String, val port: Int = 8080):
def this(port: Int) = this("localhost", port)
override def toString: String = s"$host:$port"
@main def run(): Unit =
println(Server("api.local"))
println(Server("api.local", 9000))
println(Server(3000))
val a = Server("x", 1)
val b = Server("x", 1)
println(a == b)api.local:8080
api.local:9000
localhost:3000
falseOverriding toString controls what println shows. The last line surprises everyone once: two plain class instances with the same fields are not equal, because == on a regular class compares identity. Case classes (Module 05) change that.
