Search code examples
scalatypespolymorphismexistential-type

Mapping over a list of existential types


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 IntBoxs into one unobtainable anonymous type...

Can I get what I want without casting (i.e. adder.asInstanceOf[Adder[adder.ib.type]]...?


Solution

  • 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) }