Scala Objects
In Scala, object creates a singleton — one single instance that exists for the entire lifetime of the program. You never use new with an object. The JVM creates it automatically the first time your code references it. Objects serve as utility holders, namespaces, entry points, and factory containers.
Defining a Singleton Object
object MathUtils:
val PI = 3.141592653589793
def square(n: Double): Double = n * n
def cube(n: Double): Double = n * n * n
def circleArea(r: Double): Double = PI * r * r
// No 'new' — access directly
println(MathUtils.PI) // 3.141592653589793
println(MathUtils.square(5)) // 25.0
println(MathUtils.circleArea(7)) // 153.93...
object MathUtils
│
└── Single instance in memory, shared by all code
Access: MathUtils.square(5)
Object as Application Entry Point
In Scala 2 (and still valid in Scala 3), the program entry point is a method called main inside an object. Scala 3 simplified this with @main, but the object approach works everywhere:
object App:
def main(args: Array[String]): Unit =
println("Application started")
println(s"Arguments: ${args.mkString(", ")}")
Object as Namespace
object Config:
val host = "localhost"
val port = 5432
val database = "myapp_db"
val maxPool = 10
object Messages:
val welcome = "Welcome to the app!"
val notFound = "Resource not found"
val serverError = "An error occurred. Please try again."
println(Config.host) // localhost
println(Messages.welcome) // Welcome to the app!
Object State (Careful With This)
Because an object is a singleton, any var inside it acts as global mutable state. Use this sparingly:
object Counter:
private var count = 0
def increment(): Unit = count += 1
def reset(): Unit = count = 0
def value: Int = count
Counter.increment()
Counter.increment()
Counter.increment()
println(Counter.value) // 3
Counter.reset()
println(Counter.value) // 0
Object vs Class
Object Class
────────────────────────────── ────────────────────────────────
One instance (singleton) Many instances possible
No 'new' keyword Uses 'new' to create instances
Access directly by object name Access via instance reference
Good for utilities, constants Good for modeling entities
Like Java's static methods Like Java's instance methods
Extends and Traits in Objects
An object can extend a class or implement traits:
trait Greeter:
def greet(name: String): String
object FormalGreeter extends Greeter:
def greet(name: String): String = s"Good day, $name."
object CasualGreeter extends Greeter:
def greet(name: String): String = s"Hey, $name!"
def welcome(greeter: Greeter, name: String): Unit =
println(greeter.greet(name))
welcome(FormalGreeter, "Alice") // Good day, Alice.
welcome(CasualGreeter, "Bob") // Hey, Bob!
Practical: Logger Singleton
object Logger:
private var logLevel = "INFO"
def setLevel(level: String): Unit = logLevel = level
def log(level: String, message: String): Unit =
val priority = Map("DEBUG" -> 0, "INFO" -> 1, "WARN" -> 2, "ERROR" -> 3)
val current = priority.getOrElse(logLevel, 1)
val incoming = priority.getOrElse(level, 1)
if incoming >= current then
println(s"[$level] $message")
def info(msg: String): Unit = log("INFO", msg)
def warn(msg: String): Unit = log("WARN", msg)
def error(msg: String): Unit = log("ERROR", msg)
def debug(msg: String): Unit = log("DEBUG", msg)
Logger.info("Server started on port 8080")
Logger.warn("Memory usage at 85%")
Logger.setLevel("WARN")
Logger.info("This won't print — below WARN level")
Logger.error("Disk full!")
// [INFO] Server started on port 8080
// [WARN] Memory usage at 85%
// [ERROR] Disk full!
