+1  A: 

You can write C <: Child[_].

Antoras
I guess that will work, but I think the OP is after a shortcut for Parent[C < Child[Parent[C < Child[Parent[C < Child] ... etc for infinity. :)
Synesso
As Synesso said, Child[_] won't enforce that parents and children be matched to each other.
Marcus Downing
Why do you want to use generics? Why not using parameters: class Parent(c: Child); class Child(p: Parent)
Antoras
@Synesso: how could you even instantiate such a hypothetical type?
pelotom
@Antoras: I want to make sure the parent and child types are tied together, not actual instances. The question is a simplification, perhaps too far: they are actually traits that should be applied to implementing classes.
Marcus Downing
@pelotom - with great patience.
Synesso
+3  A: 

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]
}
Daniel
That gets me past the compiler warning, but doesn't enforce the condition that parent and child class must each relate to the other.
Marcus Downing
See my answer based on abstract type members.
Marcus Downing
+3  A: 

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 {...}
}
Alexey Romanov
That looks correct. Now how would you expand that to include chains of parent -> child -> child?
Marcus Downing
This approach is successful, but I don't quite feel satisfied with it. I'm not sure I can adequately explain why.
Marcus Downing
+2  A: 

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.

Marcus Downing
+1  A: 

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
Marcus Downing