How to create inner classes in Scala

This is an excerpt from the Scala Cookbook (partially modified for the internet). This is Recipe 4.16, “How to create inner classes in Scala.”

Problem

You want to create a Scala class as an inner class to help keep the class out of your public API, or to otherwise encapsulate your code.

Solution

Declare one class inside another class. In the following example, a case class named Thing is declared inside of a class named PandorasBox:

class PandorasBox {
    case class Thing (name: String)
    var things = new collection.mutable.ArrayBuffer[Thing]()
    things += Thing("Evil Thing #1")
    things += Thing("Evil Thing #2")
    def addThing(name: String) { things += new Thing(name) }
}

This lets users of PandorasBox access the collection of things inside the box, while code outside of PandorasBox generally doesn’t have to worry about the concept of a Thing:

object ClassInAClassExample extends App {
    val p = new PandorasBox
    p.things.foreach(println)
}

As shown, you can access the things in PandorasBox with the things method. You can also add new things to PandorasBox by calling the addThing method:

p.addThing("Evil Thing #3")
p.addThing("Evil Thing #4")

Discussion

The concept of a “class within a class” is different in Scala than in Java. As described on the official Scala website, “Opposed to Java-like languages where such inner classes are members of the enclosing class, in Scala, such inner classes are bound to the outer object.” The following code demonstrates this:

object ClassInObject extends App {
    // inner classes are bound to the object
    val oc1 = new OuterClass
    val oc2 = new OuterClass
    val ic1 = new oc1.InnerClass
    val ic2 = new oc2.InnerClass
    ic1.x = 10
    ic2.x = 20
    println(s"ic1.x = ${ic1.x}")
    println(s"ic2.x = ${ic2.x}")
}

class OuterClass {
    class InnerClass {
        var x = 1
    }
}

Because inner classes are bound to their object instances, when that code is run, it prints the following output:

ic1.x = 10
ic2.x = 20

There are many other things you can do with inner classes, such as include a class inside an object or an object inside a class:

object InnerClassDemo2 extends App {

    // class inside object
    println(new OuterObject.InnerClass().x)

    // object inside class
    println(new OuterClass().InnerObject.y)

}

object OuterObject {
    class InnerClass {
      var x = 1
    }
}

class OuterClass {
    object InnerObject {
      val y = 2
    }
}

See Also