Scala by Example: Objects
Creating singletons and static-like members with this code example showing object definitions for single instances, companion objects sharing class names, factory methods using apply, private member access between companions, and lazy singleton initialization.
Code
// Singleton Object
object Config {
val version = "1.0"
def printInfo() = println(s"App v$version")
}
Config.printInfo()
// Companion Object
class Circle(val radius: Double) {
import Circle._ // Import static members
def area: Double = calculateArea(radius)
}
object Circle {
private val Pi = 3.14159
// Factory method
def apply(d: Double): Circle = new Circle(d / 2)
def calculateArea(r: Double): Double = Pi * r * r
}
val c = Circle(10.0) // Calls Circle.apply(10.0)
println(c.area)Explanation
Scala does not have static members like Java. Instead, it uses the object keyword to define singletons, which are classes with exactly one instance. Objects are initialized lazily when first accessed, not at program startup. You access object members directly using the object name, making them the natural place for global constants, utility functions, and application entry points. Objects provide a cleaner alternative to Java's static members while maintaining object-oriented principles.
When an object shares the same name as a class and is defined in the same source file, it's called a companion object. The class and its companion object can access each other's private members, enabling tight integration while maintaining encapsulation from external code. Companion objects are commonly used to define factory methods, especially the special apply method, and to hold static-like helper methods associated with the class.
The apply method in a companion object has special syntactic sugar in Scala. When you call an object like a function using ObjectName(args), the compiler translates it to ObjectName.apply(args). This is how case classes are instantiated without new, and it's a common pattern for factory methods throughout Scala libraries. This syntactic convenience makes object creation feel more natural and functional.
Code Breakdown
object Config defines singleton initialized lazily on first access.Circle shares name with class, accessing private members.def apply(...) enables calling object as function for factory pattern.Circle(10.0) syntax sugar automatically calls Circle.apply(10.0).
