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: 237
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 Car
s like Ferrari
s and Mustang
s 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