Scala programmers can define objects without first defining a class and then instantiating it. Such objects are called singletons.
For example, a queuing simulation might require a single global clock to keep track of the number of elapsed cycles:
object clock:
var cycle = 0
def tick() = cycle += 1
def time = cycle
With curly braces:
object clock {
var cycle = 0
def tick() = cycle += 1
def time = cycle
}
Since we can't instantiate classes before a program starts, how do we start the program in the first place? In Java this problem is solved by declaring main as a static method of some class. But there are no static methods or fields in Scala. However, singletons are static. Therefore, Scala programmers put main in a singleton:
object test:
def main(args: Array[String]): Unit =
for(i <- 0 to 50) clock.tick()
println("time = "
+ clock.cycle) // prints "time = 51"
Notes:
· When we start a program all singletons are created before main is executed.
· Singletons have global scope or visibility. They are visible to the entire program. For example, test doesn't need to create a pointer to clock, it can reference it directly.
· In C terminology a value (variable, function, object, etc.) is static if it has global scope (visible everywhere) and global lifetime (exists the entire time the program runs).
· Typically, a programs memory is partitioned into three segments: stack, heap, and static. Local variables reside in the stack, class instances reside in the heap, and static values reside in static memory.
· Scala provides a pre-defined App object with an implicit main method:
object test
extends App:
for(i <- 0 to 50) clock.tick
println("time = " +
clock.cycle) // prints
"time = 51"}
We can think of a singleton as a utility (aka service). A utility is an object that represents a library of related functions and values.
For example:
object conversions {
val distanceFactor = 0.6214
val weightFactor = 2.2046
def km2miles(kms: Double) = kms *
distanceFactor
def miles2kms(miles: Double) = miles /
distanceFactor
def kgs2pounds(kgs: Double) = kgs /
weightFactor
def pounds2kgs(pounds: Double) = pounds
* weightFactor
// etc.
}
Notes
· In this example I'm using the original (but still supported) syntax for declaring singletons that uses curly braces rather than indentation for specifying scopes.
· In Java a utility is usually implemented as a class in which all of the members are static.
· We can think of a utility as an object that represents a library.
· We could have declared conversions to be a class, but then we would need to instantiate it before we could use it:
class conversions { ... }
val c1 = new conversions()
val c2 = new conversions()
c1.km2miles(3.1) // = 1.89844
c2.km2miles(3.1) // = 1.89844
· We say that a class or singleton is cohesive if its properties and methods are closely related. There are degrees of cohesiveness: coincidental < logical < temporal < procedural < informational. See here for more information.