Scala recursive generics: parent [child] and child [parent]

Update : Clarified and expanded since the original question was too simplified.

I need a couple of signs, each of which refers to another, so the parent and child classes must relate to each other.

trait Parent [C <: Child] { def foo(c: C) } trait Child [P <: Parent] { def parent: P = ... def bar = parent.foo(this) } 

So that implementing classes come in pairs:

 class ActualParent extends Parent [ActualChild] { def foo(c: ActualChild) = ... } class ActualChild extends Child [ActualParent] { } 

Unfortunately, the compiler does not like these traits because generic types are not complete. Instead of C <: Child you need to say C <: Child[ something ] . Leaving them unspecified also does not work:

 trait Parent [C <: Child[_]] { def foo(c: C) } trait Child [P <: Parent[_]] { def parent: P = ... def bar = parent.foo(this) } 

Now he complains about the string parent.foo(this) because he does not know that this is of the correct type. The parent type must be Parent[this.type] to call foo in order to have the required types.

I think there should be a way to refer to the native type of an object? Or to the type that should be yourself?


Refresh . In response to @Daniel, I tried using an abstract type member in a child language to specify generic types of the parent type as follows:

 trait Parent [C <: Child] { def foo(c: C) } trait Child { type P <: Parent[this.type] def parent: P = ... def bar = parent.foo(this) } 

This does not work when I try to implement it:

 class ActualParent extends Parent [ActualChild] { def foo(c: ActualChild) = ... } class ActualChild extends Child { type P = ActualParent } 

Gives the following error:

 overriding type Parent in trait Child with bounds >: Nothing <: Parent[ActualChild.this.type] type Parent has incompatible type 

What does it mean?

+4
source share
5 answers

You can use the approach given at 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 {...} } 
+5
source

This can be done using abstract type elements.

 class Parent { type C <: Child def child: C = null.asInstanceOf[C] } class Child { type P <: Parent def parent: P = null.asInstanceOf[P] } 
+3
source

In addition to @Daniel's answer, I can use an abstract type element inside a child element to specify generic types of the parent type as follows:

 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 not used directly in generics, but in the parameter it seems fine. This approach is much shorter than the surrounding abstract class, and provides more flexible use, such as children who are also parents.

+3
source

You can write C <: Child[_] .

+1
source

Although this failed, I will record this prospectus as an answer.

Using elements of an abstract type, state boundaries for types that reference 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 is that the compiler does not connect this to the parent's child type, 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 
+1
source

All Articles