This Type allows us to type-check on a Type internal to another class. This may seem weird at first, but is very intuitive once you see it:
class Outer {
class Inner
}
val out1 = new Outer
val out1in = new out1.Inner // concrete instance, created from inside of Outer
val out2 = new Outer
val out2in = new out2.Inner // another instance of Inner, with the enclosing instance out2
// the path dependent type. The "path" is "inside out1".
type PathDep1 = out1.Inner
// type checks
val typeChecksOk: PathDep1 = out1in
// OK
val typeCheckFails: PathDep1 = out2in
// <console>:27: error: type mismatch;
// found : out2.Inner
// required: PathDep1
// (which expands to) out1.Inner
// val typeCheckFails: PathDep1 = out2in
The key to understand here is that "each Outer class has its own Inner class", so it’s a different Type - dependent on which path we use to get there.
Using this kind of typing is useful, we’re able to enforce getting the type from inside of a concrete parameter. An example of a signature using this typing would be:
class Parent {
class Child
}
class ChildrenContainer(p: Parent) {
type ChildOfThisParent = p.Child
def add(c: ChildOfThisParent) = ???
}
Using the path dependent type we have now encoded in the type system, the logic, that this container should only contain children of this parent - and not "any parent".
We’ll see how to require the "child of any parent" Type in the section about Type Projections soon.