You can write C <: Child[_]
.
It can be done with abstract type members.
class Parent {
type C <: Child
def child: C = null.asInstanceOf[C]
}
class Child {
type P <: Parent
def parent: P = null.asInstanceOf[P]
}
You can use the approach given in http://programming-scala.labs.oreilly.com/ch13.html:
abstract class ParentChildPair {
type C <: Child
type P <: Parent
trait Child {self: C =>
def parent: P
}
trait Parent {self: P =>
def child: C
}
}
class ActualParentChildPair1 {
type C = Child1
type P = Parent1
class Child1 extends Child {...}
class Parent1 extends Parent {...}
}
Further to @Daniel's answer, I can use an abstract type member within the child to state the generic types of the parent type like this:
trait Parent [C <: Child] {
def foo(c: C)
}
trait Child {
type P <: Parent[this.type]
def parent: P = ...
def bar = parent.foo(this)
}
this.type
isn't usable directly in generics, but in a parameter it seems to be fine. This approach is a lot less long-winded than the surrounding abstract class, and allows more flexible uses such as children that are also parents.
Even though it wasn't successful, I'll record this avenue as an answer.
Using abstract type members, state bounds for the types referring back to this.type
:
trait Parent {
type C <: Child { type P <: this.type }
def foo(c: C)
}
trait Child {
type P <: Parent { type C <: this.type }
def parent: P
def bar = parent.foo(this)
}
class ActualParent extends Parent {
type C = ActualChild
def foo(c: ActualChild) = println("Hello")
}
class ActualChild extends Child {
type P = ActualParent
def parent = new ActualParent
}
The problem here is that the compiler doesn't connect this
with the child type of the parent, so calling parent.foo(this)
results in:
type mismatch
found : Child.this.type (with underlying type Child)
required: _3.C where val _3: Child.this.P