- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
A Tour of Scala: Inner Classes
Created by admin on 2008-07-05.
Updated: 2009-03-06, 10:30
In Scala it is possible to let classes have other classes as members. 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. To illustrate the difference, we quickly sketch the implementation of a graph datatype:
class Graph { class Node { var connectedNodes: List[Node] = Nil def connectTo(node: Node) { if (connectedNodes.find(node.equals).isEmpty) { connectedNodes = node :: connectedNodes } } } var nodes: List[Node] = Nil def newNode: Node = { val res = new Node nodes = res :: nodes res } }
In our program, graphs are represented by a list of nodes. Nodes are objects of inner class Node
. Each node has a list of neighbours, which get stored in the list connectedNodes
. Now we can set up a graph with some nodes and connect the nodes incrementally:
object GraphTest extends Application { val g = new Graph val n1 = g.newNode val n2 = g.newNode val n3 = g.newNode n1.connectTo(n2) n3.connectTo(n1) }
We now enrich the following example with types to state explicitly what the type of the various defined entities is:
object GraphTest extends Application { val g: Graph = new Graph val n1: g.Node = g.newNode val n2: g.Node = g.newNode val n3: g.Node = g.newNode n1.connectTo(n2) n3.connectTo(n1) }
This code clearly shows that a node type is prefixed with its outer instance (which is object g
in our example). If we now have two graphs, the type system of Scala does not allow us to mix nodes defined within one graph with the nodes of another graph, since the nodes of the other graph have a different type.
Here is an illegal program:
object IllegalGraphTest extends Application { val g: Graph = new Graph val n1: g.Node = g.newNode val n2: g.Node = g.newNode n1.connectTo(n2) // legal val h: Graph = new Graph val n3: h.Node = h.newNode n1.connectTo(n3) // illegal! }
Please note that in Java the last line in the previous example program would have been correct. For nodes of both graphs, Java would assign the same type Graph.Node
; i.e. Node
is prefixed with class Graph
. In Scala such a type can be expressed as well, it is written Graph#Node
. If we want to be able to connect nodes of different graphs, we have to change the definition of our initial graph implementation in the following way:
class Graph { class Node { var connectedNodes: List[Graph#Node] = Nil def connectTo(node: Graph#Node) { if (connectedNodes.find(node.equals).isEmpty) { connectedNodes = node :: connectedNodes } } } var nodes: List[Node] = Nil def newNode: Node = { val res = new Node nodes = res :: nodes res } }
Please note that this program doesn't allow us to attach a node to two different graphs. If we want to remove this restriction as well, we have to change the type of variable nodes
and the return type of method newNode
toGraph#Node
.