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