I have a list of existientially-typed objects I want to map over. Something like this:
sealed abstract class IntBox(val v: Int)
case object IB1 extends IntBox(1)
case object IB2 extends IntBox(2)
case class Adder[A <: IntBox](ib: A, v: Int) {
def add(i: A) = v + i.v
}
val adders: List[Adder[_ <: IntBox]] = List(Adder(IB1, 0), Adder(IB2, 0))
adders.map(adder => adder.add(adder.ib))
However, I'm getting an error like
found: adder.ib.type
required: _$1
I feel it's something like because the map
somehow unifies the different IntBox
s into one unobtainable anonymous type...
Can I get what I want without casting (i.e. adder.asInstanceOf[Adder[adder.ib.type]]...
?
The type is not unobtainable, you can get it using type pattern matching:
adders.map{ case a: Adder[t] => a.add(a.ib) }
Here, the existential type parameter is bound to type variable t
, and the compiler can correctly infer additional properties of t
that it cannot infer for the whole list.
Refer to section 8.3.1 of the Specification for more details.
Full code with trait
replaced by class
to make it compile
sealed abstract class IntBox(val v: Int)
case object IB1 extends IntBox(1)
case object IB2 extends IntBox(2)
case class Adder[A <: IntBox](ib: A, v: Int) {
def add(i: A) = v + i.v
}
val adders: List[Adder[_ <: IntBox]] = List(Adder(IB1, 0), Adder(IB2, 0))
adders.map{ case a: Adder[t] => a.add(a.ib) }