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
        ^

      

+3


source to share


3 answers


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

      

+1


source


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

      

0


source


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
}

      

0


source







All Articles