Reputation: 568
I defined a type class like this:
/** Type class */
trait Drivable[V <: Vehicle]{
def drive(v:V)
}
It request a subtype of Vehicle as parameter of drive
function. And now I'm trying to use this type class to the Vehicle
itself.
/** ADT */
sealed trait Vehicle{
def drive[V <: Vehicle](implicit d: Drivable[V]): Unit = d.drive(this)
}
the compiler complains:
Error:(15, 74) type mismatch;
found : Vehicle.this.type (with underlying type Vehicle)
required: V
def drive[V <: Vehicle](implicit d: Drivable[V]): Unit = d.drive(this)
It works if I force cast this
to V
def drive[V <: Vehicle](implicit d: Drivable[V]): Unit = d.drive(this.asInstanceOf[V])
But I hate doing so. Or, it also works if I just put it in the case class:
final case class Car(name:String) extends Vehicle {
def drive(implicit d: Drivable[Car]): Unit = d.drive(this)
}
But imaging I have many case classes
, I have to repeat this in everyone.
What's the correct to use this type class in the base trait?
Upvotes: 0
Views: 91
Reputation: 51648
Either make drive
an extension method
sealed trait Vehicle
implicit class DrivableOps[V <: Vehicle](val vehicle: V) extends AnyVal {
def drive(implicit d: Drivable[V]): Unit = d.drive(vehicle)
}
or make V
a type member of the trait rather than type parameter of the method
sealed trait Vehicle {
type V >: this.type <: Vehicle
def drive(implicit d: Drivable[V]): Unit = d.drive(this)
}
case class Bus() extends Vehicle {
override type V = Bus
}
case class Car() extends Vehicle {
override type V = Car
}
Type V
can be generated automatically:
//libraryDependencies += "com.github.dmytromitin" %% "auxify-macros" % "0.8"
import com.github.dmytromitin.auxify.macros.self
@self sealed trait Vehicle {
def drive(implicit d: Drivable[Self]): Unit = d.drive(this)
}
@self case class Bus() extends Vehicle
@self case class Car() extends Vehicle
Upvotes: 3