How to create static members with Scala companion objects

This is an excerpt from the 1st Edition of the Scala Cookbook (partially modified for the internet). This is Recipe 6.6, “How to create static members with Scala companion objects.”

Problem

You want to create a Scala class that has both instance methods and static methods, but unlike Java, Scala does not have a static keyword.

Solution

Define non-static (instance) members in your class, and define members that you want to appear as “static” members in an object that has the same name as the class, and is in the same file as the class. This object is known as a companion object.

Using this approach lets you create what appear to be static members on a class (both fields and methods), as shown in this example:

// Pizza class
class Pizza (var crustType: String) {
    override def toString = "Crust type is " + crustType
}

// companion object
object Pizza {
    val CRUST_TYPE_THIN = "thin"
    val CRUST_TYPE_THICK = "thick"
    def getFoo = "Foo"
}

With the Pizza class and Pizza object defined in the same file (presumably named Pizza.scala), members of the Pizza object can be accessed just as static members of a Java class:

println(Pizza.CRUST_TYPE_THIN)
println(Pizza.getFoo)

You can also create a new Pizza instance and use it as usual:

var p = new Pizza(Pizza.CRUST_TYPE_THICK)
println(p)

If you’re coming to Scala from a language other than Java, “static” methods in Java are methods that can be called directly on a class, without requiring an instance of the class. For instance, here’s an example of a method named increment in a Scala object named StringUtils:

object StringUtils {
    def increment(s: String) = s.map(c => (c + 1).toChar)
}

Because it’s defined inside an object (not a class), the increment method can be called directly on the StringUtils object, without requiring an instance of StringUtils to be created:

scala> StringUtils.increment("HAL")
res0: String = IBM

In fact, when an object is defined like this without a corresponding class, you can’t create an instance of it. This line of code won’t compile:

val utils = new StringUtils

Discussion

Although this approach is different than Java, the recipe is straightforward:

  • Define your class and object in the same file, giving them the same name.
  • Define members that should appear to be “static” in the object.
  • Define non-static (instance) members in the class.

Accessing private members

It’s also important to know that a class and its companion object can access each other’s private members. In the following code, the “static” method double in the object can access the private variable secret of the class Foo:

class Foo {
    private val secret = 2
}

object Foo {
    // access the private class field 'secret'
    def double(foo: Foo) = foo.secret * 2
}

object Driver extends App {
    val f = new Foo
    println(Foo.double(f))  // prints 4
}

Similarly, in the following code, the instance member printObj can access the private field obj of the object Foo:

class Foo {
    // access the private object field 'obj'
    def printObj { println(s"I can see ${Foo.obj}") }
}

object Foo {
    private val obj = "Foo's object"
}

object Driver extends App {
    val f = new Foo
    f.printObj
}

The Scala Cookbook

This tutorial is sponsored by the Scala Cookbook, which I wrote for O’Reilly: