Given the following scala code:
sealed trait Color
case object Red extends Color
case object Blue extends Color
sealed trait Car {
def isBroken: Boolean
You should move your data to the type-level then:
trait Bool
trait T extends Bool
trait F extends Bool
trait Color
trait Red extends Color
trait Blue extends Color
trait Car[Clr <: Color, Brkn <: Bool]
def fixBrokenCar[Cr <: Car[Red, T]](c: Cr) = new Car[Red, F]{}
scala> fixBrokenCar(new Car[Blue, T]{})
:16: error: inferred type arguments [Car[Blue,T]] do not conform to method fixBrokenCar's type parameter bounds [Cr <: Car[Red,T]]
fixBrokenCar(new Car[Blue, T]{})
^
:16: error: type mismatch;
found : Car[Blue,T]
required: Cr
fixBrokenCar(new Car[Blue, T]{})
^
scala> fixBrokenCar(new Car[Red, T]{})
res3: Car[Red,F] = $anon$1@67d9a642
To "destroy" it:
def destroyRedCar(c: Car[Red, _]) = true
scala> destroyRedCar(fixBrokenCar(new Car[Red, T]{}))
res10: Boolean = true
scala> destroyRedCar(new Car[Red, T]{})
res11: Boolean = true
scala> destroyRedCar(new Car[Blue, T]{})
:15: error: type mismatch;
found : Car[Blue,T]
required: Car[Red, ?]
destroyRedCar(new Car[Blue, T]{})
^
If you need to "mutate" Cr
type (construct one type from another, more precisely):
trait Car[Clr <: Color, Brkn <: Bool] {
type Copy[C <: Color, B <: Bool] <: Car[C,B] // define "copy" type-method
}
trait BrandedCar[Clr <: Color, Brkn <: Bool] extends Car[Clr, Brkn] {
type Copy[C <: Color, B <: Bool] = BrandedCar[C, B] // implement "copy" type-method
def brand: String = "default"
}
def fixBrokenCar[Cr <: Car[Red, T]](c: Cr) = c.asInstanceOf[Cr#Copy[Red, F]]
def checkBrandedCar(c: BrandedCar[_, F]) = true // accepts only branded and fixed
scala> checkBrandedCar(new BrandedCar[Red, F]{})
res10: Boolean = true
scala> checkBrandedCar(new Car[Red, F]{})
:15: error: type mismatch;
found : Car[Red,F]
required: BrandedCar[?, F]
checkBrandedCar(new Car[Red, F]{})
^
scala> checkBrandedCar(fixBrokenCar(new BrandedCar[Red, T]{}))
res12: Boolean = true
You may also define some def copy[C <: Color, B <: Bool]: Copy[C, B]
method inside Car
's trait (like in case classes) instead of just asInstanceOf
.