Scala Classes 3
Nested classes in Scala
In this third part regarding Scala classes we review nested classes.
In Scala, you can nest just about anything inside anything [1]. For example we can define functions inside other functions, and classes inside other classes. We discuss the latter feature here.
import scala.collection.mutable.ArrayBuffer
class Grid{
class Element(val idx: Int){
val children = new ArrayBuffer[Element]
}
private val elements = new ArrayBuffer[Element]
def addElement() : Unit = {
val element = new Element(this.elements.size)
elements += element
}
def addElement(element: Element){
elements += element
}
def nElements(): Int = this.elements.size
}
val grid = new Grid
grid.addElement()
println(" Number of elements " + grid.nElements)
In Scala, each instance has its own class Element
, just like each instance has its own field members [1]. You can see this below
val grid_2 = new Grid
grid.addElement(new grid_2.Element(0))
Assuming that grid
holds quad elemennts and grid_2
holds triangular elements this behaviour makes sense. However, we may want to remove this behaviour. We can do this in two ways [1]
- Use a companion object
- Use type projection
object Grid{
class Element(val idx: Int){
val children = new ArrayBuffer[Element]
}
}
class Grid{
private val elements = new ArrayBuffer[Grid.Element]
def addElement() : Unit = {
val element = new Grid.Element(this.elements.size)
elements += element
}
def addElement(element: Grid.Element){
elements += element
}
def nElements(): Int = this.elements.size
}
With type projection, we write our class as shown below
class Grid{
class Element(val idx: Int){
val children = new ArrayBuffer[Element]
}
private val elements = new ArrayBuffer[Element]
def addElement() : Unit = {
val element = new Element(this.elements.size)
elements += element
}
def addElement(element: Element){
elements += element
}
def nElements(): Int = this.elements.size
}
Type projection means, for our case, Element
from any Grid
val grid = new Grid
val grid2 = new Grid
grid.addElement(new grid_2.Element(0))
Finally, in a nested class, we can access the this
reference of the enclosing
class as EnclosingClass.this
[1]. This is similar to Java. Furthermore, we can establish an alias for that reference as shown below
class Grid{ outer =>
class Element(val idx: Int){
val children = new ArrayBuffer[Element]
}
private val elements = new ArrayBuffer[Element]
def addElement() : Unit = {
val element = new Element(this.elements.size)
elements += element
}
def addElement(element: Element){
elements += element
}
def nElements(): Int = this.elements.size
}
The class Grid{ outer =>
syntax makes the variable outer refer to
Grid.this
. Note that we can choose any name for this variable. The name self
is common, but perhaps confusing when used with nested classes [1].
- Cay Horstmann,
Scala for the Impatient 1st Edition