Scala: Correcting type inference of representation type over if statement
        Posted  
        
            by 
                drhagen
            
        on Stack Overflow
        
        See other posts from Stack Overflow
        
            or by drhagen
        
        
        
        Published on 2012-06-30T21:04:02Z
        Indexed on 
            2012/06/30
            21:16 UTC
        
        
        Read the original article
        Hit count: 303
        
scala
This is a follow-up to two questions on representation types, which are type parameters of a trait designed to represent the type underlying a bounded type member (or something like that). I've had success creating instances of classes, e.g ConcreteGarage, that have instances cars of bounded type members CarType.
trait Garage {
  type CarType <: Car[CarType]
  def cars: Seq[CarType]
  def copy(cars: Seq[CarType]): Garage
  def refuel(car: CarType, fuel: CarType#FuelType): Garage = copy(
    cars.map {
      case `car` => car.refuel(fuel)
      case other => other
    })
}
class ConcreteGarage[C <: Car[C]](val cars: Seq[C]) extends Garage {
  type CarType = C
  def copy(cars: Seq[C]) = new ConcreteGarage(cars)
}
trait Car[C <: Car[C]] {
  type FuelType <: Fuel
  def fuel: FuelType
  def copy(fuel: C#FuelType): C
  def refuel(fuel: C#FuelType): C = copy(fuel)
}
class Ferrari(val fuel: Benzin) extends Car[Ferrari] {
  type FuelType = Benzin
  def copy(fuel: Benzin) = new Ferrari(fuel)
}
class Mustang(val fuel: Benzin) extends Car[Mustang] {
  type FuelType = Benzin
  def copy(fuel: Benzin) = new Mustang(fuel)
}
trait Fuel
case class Benzin() extends Fuel
I can easily create instances of Cars like Ferraris and Mustangs and put them into a ConcreteGarage, as long as it's simple:
val newFerrari = new Ferrari(Benzin())
val newMustang = new Mustang(Benzin())
val ferrariGarage = new ConcreteGarage(Seq(newFerrari))
val mustangGarage = new ConcreteGarage(Seq(newMustang))
However, if I merely return one or the other, based on a flag, and try to put the result into a garage, it fails:
val likesFord = true
val new_car = if (likesFord) newFerrari else newMustang
val switchedGarage = new ConcreteGarage(Seq(new_car)) // Fails here
The switch alone works fine, it is the call to ConcreteGarage constructor that fails with the rather mystical error:
error: inferred type arguments [this.Car[_ >: this.Ferrari with this.Mustang <: this.Car[_ >: this.Ferrari with this.Mustang <: ScalaObject]{def fuel: this.Benzin; type FuelType<: this.Benzin}]{def fuel: this.Benzin; type FuelType<: this.Benzin}] do not conform to class ConcreteGarage's type parameter bounds [C <: this.Car[C]]
val switchedGarage = new ConcreteGarage(Seq(new_car)) // Fails here
                     ^
I have tried putting those magic [C <: Car[C]] representation type parameters everywhere, but without success in finding the magic spot.
© Stack Overflow or respective owner