The Basics of Singleton Objects in Scala
By: Alonso Del Arte
Tags: Singleton Pattern, Scala, Object Oriented Design

Photo by Will Porada on Unsplash

Scala doesn’t have the static keyword like Java does. For an experienced Java programmer learning Scala, this raises a number of questions about programming in Scala things we take for granted in Java, such as:

How do you write a “static” utility class like java.lang.Math or JUnit’s Assertions ?

or JUnit’s ? How do you write a class that can only be instantiated once in a session?

How do you write a “main method” for a command line program?

How do you write “factory methods”?

The answer for each of these involves a special class declared with the object keyword instead of the class keyword. Please let me know at the end if you have a similar question that goes unanswered.

Assuming there are no compilation errors, the Scala compiler will compile two Java bytecode files for each Scala singleton object. But we can choose to view each such pair as a single class that is final, has only static functions and procedures, and has a private constructor that can only be called once.

If we wanted to reinvent the wheel of java.lang.Math in Scala, we’d write something like this:

package calculators object Math {

val E: Double = 2.718281828459045

val PI: Double = 3.141592653589793 def abs(n: Int): Int = if (n < 0) -n else n // TODO: Write abs(Long), abs(Float), abs(Double) // TODO: Write trigonometric functions // TODO: Write root, power functions

// etc.,etc. }

Of course we don’t actually need to reinvent this particular wheel for our Scala programs, we can just use java.lang.Math in the same way we use it in our Java programs.

If we went ahead with our own Math , we would be able to use its functions like we use the functions from java.lang.Math , except we’d have to do something about the namespace if we don’t want to have to type the fully qualified name every time.

Because a class declared this way is marked final by the Scala compiler, it can’t be extended, and because its constructor is private, we can’t circumvent the prohibition against a second instance using Java. The following Java line

calculators.Math secondMath = new calculators.Math(); // ERROR

would fail to compile just the same as

java.lang.Math secondMath = new java.lang.Math(); // ERROR

would also fail to compile.

To declare a “main method” for a command line program, you write a singleton object with several elements of the familiar “public static void main” formula. The Hello World program is a good example of this:

object HelloWorld { def main(args: Array[String]): Unit = {

println("Hello, world!")

} }

The only bad thing about the Hello World example is that it doesn’t illustrate actually doing anything with String[] args . How about a palindrome checker? Like this one:

package textops object PalindromeChecker { def isPalindromic(s: String): Boolean = {

s == s.reverse

} def main(args: Array[String]): Unit = {

for (arg <- args) {

print("\"" + arg + "\"")

if (isPalindromic(arg)) {

println(" IS palindromic")

} else {

println(" is NOT palindromic")

}

}

} }

Thanks to an implicit conversion to WrappedString , we don’t have to worry about the fact that java.lang.String doesn’t have a reverse() function. Also thanks to M. F. Hasler for a refactoring suggestion.

I mentioned earlier that the Scala compiler generates two bytecode files for each singleton object. In this case, that means PalindromeChecker.class and PalindromeChecker$.class.

To run this from the command line, we’ll need the one without the dollar sign, but if you’re using the java command rather than the scala command, you will need to include the Scala Library JAR on the class path.

C:\Users\AL\IdeaProjects\BasicExercises\out\production\...>java

-cp .;"C:\Program Files (x86)\scala\lib\scala-library.jar" textops.PalindromeChecker kayak radars 123454321 123454322 "ABC CBA"

"kayak" IS palindromic

"radars" is NOT palindromic

"123454321" IS palindromic

"123454322" is NOT palindromic

"ABC CBA" IS palindromic

Note that this is case-sensitive. If you want to make it case-insensitive, or even add command line options for that, you can, but that’s outside the scope of this article…

On second thought, I should include it in, to help illustrate that singleton objects are actually classes.

package textops object PalindromeChecker {

var caseSensitive: Boolean = true def isPalindromic(s: String): Boolean = {

val str = if (this.caseSensitive) s else s.toLowerCase

str == str.reverse

} def main(args: Array[String]): Unit = {

for (arg <- args) {

print("\"" + arg + "\" ")

arg.toLowerCase match {

case "-case" => this.caseSensitive = true

case "-nocase" => this.caseSensitive = false

case _ => if (isPalindromic(arg)) {

println("IS palindromic")

} else {

println("is NOT palindromic")

}

}

}

} }

I don’t like that isPalindromic() is no longer a pure function. I should probably refactor… but that really is a topic for another article.

Notice the use of “ this ” to refer to caseSensitive . Does that mean that caseSensitive is not considered static by the Java Virtual Machine? Well… yes and no: it’s static in PalindromeChecker.class but it is not static in PalindromeChecker$.class.

We really don’t need to worry about this particular detail if we’re only working in Scala. This may or may not be a problem for interoperability with Java, but maybe it’s going beyond the basics of singleton objects in Scala.

Scala singleton objects very much have class: they fully participate in the Scala type system. If nothing else, a singleton object tacitly extends AnyRef (Scala’s alias for java.lang.Object ) and Any .

The fact that singleton objects can extend regular classes is a point that deserves some emphasis.

For the example, I’m going to use the ComplexNumber class. Complex numbers are actually quite simple, but I’m not going to go in depth on the mathematics.

One important points for this example is that a complex number has a “real” part and an “imaginary” part. For the sake of expediency, I’m going to use 64-bit floating point numbers to represent the real and imaginary parts of a complex number.

class ComplexNumber(val re: Double, val im: Double) {



override def toString: String = this.re.toString + " + " +

this.im.toString + "i"



def +(addend: ComplexNumber): ComplexNumber =

new ComplexNumber(this.re + addend.re, this.im + addend.im)



def *(multiplicand: ComplexNumber): ComplexNumber = {

val multRe = this.re * multiplicand.re -

this.im * multiplicand.im

val multIm = this.re * multiplicand.im +

this.im * multiplicand.re

new ComplexNumber(multRe, multIm)

}



}

I ask that you accept it on faith that I have correctly implemented the arithmetic of complex numbers (addition and multiplication) here. The toString() override leaves something to be desired, but it’ll do for the example here.

The Greek letter ω (lowercase omega) is often used to represent the special complex number −1/2 + (√−3)/2. That number is special because ω³ = 1.

Normally I would instantiate a new ComplexNumber , but here I’m going to use a singleton object that extends ComplexNumber .

object Omega extends ComplexNumber(-0.5, Math.sqrt(3)/2) {



override def toString: String = "ω"



}

Because the 64-bit floating point number system is inherently imprecise, we’re going to need a numeric adjustment to get ω³ right. But let’s use a run-of-the-mill ComplexNumber instance for that purpose.

val adjustment = new ComplexNumber(2.220446049250313E-16, -1.1102230246251565E-16) Omega * Omega * Omega + adjustment

That last line should give 1.0 + 0.0i as a result. That is, exactly 1. To save you some typing, I’ve made the complex number example into a Scastie snippet.

Obviously adjustment is an instance of ComplexNumber . So is Omega :

scala> Omega.isInstanceOf[ComplexNumber]

res3: Boolean = true

But Omega ’s runtime class is obviously not ComplexNumber . Remember that java.lang.Object has the getClass() function, which we can use to query the runtime class of any object:

scala> adjustment.getClass

res1: Class[_ <: ComplexNumber] = class ComplexNumber scala> Omega.getClass

res2: Class[_ <: Omega.type] = class Omega$

Note that I didn’t include an equals() override in ComplexNumber . For a real world use case (e.g., electrical engineering, applied physics), I would probably use getClass() in the equals() override, but I wouldn’t make special singleton objects for special numbers like ω.

Still, it’s frequently useful to have different but closely related classes, to take advantage of polymorphism, which is supposed to be one of the advantages of object-oriented programming.

This often leads to situations in which the closely related classes have constructors that seem identical, and it would be nice to have some kind of “factory method” which chooses the right constructor to use.

For example, let’s say we have a RegularConnection class and a SecureConnection class, which are different enough to merit their own separate classes, but alike enough to have an immediate abstract superclass in common, the Connection class.

Let’s say the Connection constructor takes just one parameter, a ResourceLocator instance. The RegularConnection and SecureConnection constructors also both take only one parameter, a ResourceLocator instance to pass on to the superclass constructor.

But if the RegularConnection constructor receives a ResourceLocator instance with a secure protocol, it throws a runtime exception, and so does the SecureConnection constructor if it receives a ResourceLocator instance with a regular protocol.

We would like to have a “factory method” which takes a ResourceLocator instance and returns an instance of the appropriate Connection subclass. If this was a Java project, we would probably write a static factory function in the Connection class.

But in a Scala project, what we would do is write an apply() function in the Connection companion object. A companion object is a singleton object with the same name as the class as it accompanies. It generally does not explicitly extend any classes nor implements any traits (interfaces).

The source of the companion object must be written in the same file as the source of the class it accompanies (this is a requirement).

The Scala compiler then generates two bytecode files. In this example, that would be Connection.class and Connection$.class.

I generally place the companion object source after a package declaration but before the source of the class it accompanies. This is by no means required.

Suppose that ResourceLocator is actually an abstract class, and the kind of protocol is determined by the ResourceLocator subclass. Then apply() can use type matching in a Match-Case statement to determine which Connection subclass constructor to use.

object Connection { def apply(resLoc: ResourceLocator): Connection = {

resLoc match {

case regResLoc: RegularResourceLocator =>

new RegularConnection(regResLoc)

case secResLoc: SecureResourceLocator =>

new SecureConnection(secResLoc)

case _ => throw new UnsupportedProtocolException(resLoc)

}

} }

Then, if url is a ResourceLocator instance, we can define a new Connection instance like this

val conn = Connection.apply(url)

or even briefer

val conn = Connection(url)

Companion objects are also good for housing implicit conversions. That’s a topic for another article.