I have a trait and a case class implementing it. One of the features of the trait that the implementations override is a default value. I can't find a good way to access this default value from a class that is parametrized by a specific implementation of that trait.
This is minimal code, so it doesn't really demonstrate the motivation anymore, but it does demonstrate the error:
import scala.language.implicitConversions
trait Distance[T] {
val Zero: T
def +( that: T ): T
}
case class DoubleDistance( val v: Double ) extends Distance[DoubleDistance] {
val Zero = DoubleDistance( 0.0 )
def +( that: DoubleDistance ) = DoubleDistance( v + that.v )
}
object DistanceImplicits {
implicit def DoubleToDistance( v: Double ) = new DoubleDistance( v )
}
class User[T<:Distance[T]] {
val default: T = T.Zero // This line gives me a compilation error
}
The error I get is
not found: value T
When I needed to construct an Array[T]
inside my User
class I could get that to work by adding implicit typetag:ClassTag[T]
to my arguments, but that doesn't seem to have any effect here.
First, why this doesn't work: consider a different implementation of Distance
.
case class DoubleDistance1(val v: Double) extends Distance[DoubleDistance1] {
val Zero = this
def +(that: DoubleDistance1) = ??? // doesn't matter
}
What would you expect DoubleDistance1.Zero
to mean? You can make it work using a "type class":
trait DistanceOps[T] {
val zero: T
def add(d1: T, d2: T): T
}
// just to let you write distance1 + distance2
implicit class RichDistance[T](d: T)(implicit ops: DistanceOps[T]) {
def +(other: T) = ops.add(d, other)
}
case class DoubleDistance(v: Double)
object DoubleDistance {
implicit object DoubleDistanceOps extends DistanceOps[DoubleDistance] {
val zero = DoubleDistance(0.0)
def add(d1: DoubleDistance, d2: DoubleDistance) = DoubleDistance(d1.v + d2.v)
}
}
// how to use
class User[T](implicit ops: DistanceOps[T]) {
val default: T = ops.zero
}
This looks like a classic use case for the type class pattern . Rather than associating an instance of the Distance
trait with each value of interest, you associate one with each type of interest:
trait Distance[T] {
val Zero: T
def +( a: T, b: T ): T
}
implicit object DoubleDistance extends Distance[Double] {
val Zero = 0.0
def +( a: Double, b: Double ) = a + b
}
class User[T : Distance] {
val default: T = implicitly[Distance[T]].Zero
}
Where is that Zero supposed to come from? Are you looking to do something like this?
class User[T<:Distance[T]] {
self:Distance[T] =>
val default: T = Zero
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.