I have a Scala compiler error puzzle that I can't figure out. For reasons not given here, I need to declare my classes using the curiously recurring template pattern. Some of my classes need to contain others as parameters. For example, a stripped down version of my code looks like this:
trait Container[C <: Container[C]] {
def stuff: C
}
trait Aggregation {
def fill(x: Double): Unit
}
class Counted extends Container[Counted] {
def stuff = this
}
class Counting extends Container[Counting] with Aggregation {
def stuff = this
def fill(x: Double) { }
}
class Binned[V <: Container[V]](v: V) extends Container[Binned[V]] {
def stuff = this
def substuff = v
}
class Binning[V <: Container[V] with Aggregation](v: V) extends Container[Binning[V]] with Aggregation {
def stuff = this
def substuff = v
def fill(x: Double) { }
}
The above works fine. Now I want to add an abstract type from each -ing to each -ed:
trait Container[C <: Container[C]] {
type Ed <: Container[Ed]
def stuff: C
}
trait Aggregation {
def fill(x: Double): Unit
}
class Counted extends Container[Counted] {
type Ed = Counted
def stuff = this
}
class Counting extends Container[Counting] with Aggregation {
type Ed = Counted
def stuff = this
def fill(x: Double) { }
}
class Binned[V <: Container[V]](v: V) extends Container[Binned[V]] {
type Ed = Binned[V]
def stuff = this
def substuff = v
}
class Binning[V <: Container[V] with Aggregation](v: V) extends Container[Binning[V]] with Aggregation {
type Ed = Binned[V#Ed]
def stuff = this
def substuff = v
def fill(x: Double) { }
}
and the compiler has the nerve to tell me
<console>:34: error: type arguments [V#Ed] do not conform to class Binned's type parameter bounds [V <: Container[V]]
type Ed = Binned[V#Ed]
when Ed
is clearly <: Container[Ed]
for all Containers
.
Strictly speaking, type Ed
is only needed on Containers with Aggregation
, and if I move it there, I get the same error.
Does anybody know how I can state my intention to the compiler?
class Binning[V <: Container[V] with Aggregation](val v: V) extends Container[Binning[V]] with Aggregation {
type Ed = Binned[v.Ed]
def stuff = this
def substuff = v
def fill(x: Double) { }
}
works. But it does seem to me like your version should compile as well.