Upper bounds in Scala
I am trying to set upper bounds for a variable.
trait Container {
type A <: Number
def value: A
}
Then when I try to get the value for
object AnyNumber extends Container {
def value = 2
}
I am getting this error
<console>:25: error: overriding type A in trait Container with bounds <: Number;
type A has incompatible type
type A = Int
^
source to share
You are getting this error because it is Int
not a subtype Number
, which is the hindrance you are putting.
If you want to use type members that are implicitly convertible to a numeric type, I would use Numeric[A]
with implicit evidence in value
:
trait Container {
type A
def value(implicit ev: Numeric[A]): A
}
object AnyNumber extends Container {
type A = Int
override def value(implicit ev: Numeric[Int]): Int = 2
}
Note. I used Numeric[A]
instead Number
, which is equivalent to Scala. Now this will work:
def main(args: Array[String]): Unit = {
val intRes = AnyNumber.value
}
But trying to use this with String
will not compile:
def main(args: Array[String]): Unit = {
val strRes = StringNumber.value
}
Results in:
Error:(24, 31) could not find implicit value for parameter ev: Numeric[String]
val strRes = StringNumber.value
source to share
scala.Int
extends only scala.AnyVal
, and the upper limit is java.lang.Number
.
One way to solve is to use java.lang.Integer
instead scala.Int
as it satisfies your boundary ( java.lang.Number
)
eg.
trait Container {
type A <: Number
def value: A
}
object AnyNumber extends Container {
type A = Integer
def value = 2
}
AnyNumber.value shouldBe 2
source to share
If it is Container
acceptable for it to be a class instead of a trait, the following is close to Yuval's answer, but more ergonomic:
abstract class Container[A: Numeric] {
// optional, if you need a type member specifically
type _A = A
def value: A
}
object AnyNumber extends Container[Int] {
def value = 2
}
If you want to hide the shared parameter from the API, you can do this:
sealed trait Container {
type A
val ev: Numeric[A]
def value: A
}
abstract class ContainerImpl[B](implicit val ev: Numeric[B]) extends Container {
type A = B
}
source to share