How can I do arithmetics on classes included in a type hierarchy?
I have been trying to store different types of metrics in summaries, so that I could compute aggregates on each metric collection.
In the following I show my attempts at implementation:
In my first attempt I used only a simple class hierarchy
sealed trait Metric {
def getValue(): Number = ???
}
class Counter(count: Int) extends Metric {
override def getValue() : Int = count
}
class Meter(rate: Double) extends Metric {
override def getValue() : Double = rate
}
class Container(val key: String, x : Metric, val y : Metric) {
// ERROR: Type mismatch expected: String actually: Number
def combine(): Number = x.getValue + y.getValue
}
object Main {
var list : List[Container] = List()
var res : Map[String, Number] = list.map(x => x.key -> x.combine()).toMap
}
My second attempt used generics
sealed trait Metric2[M] {
def getValue(): M = ???
}
class Counter2(count: Int) extends Metric2[Int] {
override def getValue() : Int = count
}
class Meter2(rate: Double) extends Metric2[Double] {
override def getValue() : Double = rate
}
class Container2[T](val key : String, x : Metric2[T], y: Metric2[T]) {
// ERROR: Type mismatch expected: String actually: Number
def combine(): T = x.getValue + y.getValue
}
object Main2 {
var list2 : List[Container2[Number]] = List()
var res : Map[String, Number] = list2.map(x => x.key -> x.combine()).toMap
}
The errors are highlighted in the code.
To my understanding the Number class is not actually part of the scala type hierarchy and instead Numeric shoud be used. Maybe this is the place where my code takes a wrong turn. However I could not find a good tutorial on the usage of Numeric. Any hints are appreciated!
[EDIT:] Thanks to Alexey Romanov for the solution. I specified two versions of the container, one with implicts and context and one without.
sealed abstract class Metric[M] {
abstract def value(): M
}
class Counter(count: Int) extends Metric[Int] {
override def value() : Int = count
}
class Meter(rate: Double) extends Metric[Double] {
override def value() : Double = rate
}
class Container[T](val key : String, x : Metric[T], y: Metric[T])(implicit ev: Numeric[T]) {
def combine(): T = implicitly[Numeric[T]].plus(x.value, y.value)
}
class Container2[T: Numeric](val key : String, x : Metric[T], y: Metric[T]) {
import scala.Numeric.Implicits._
def combine(): T = x.value + y.value
}
object Main {
var list : List[Container[Number]] = List()
var res : Map[String, Number] = list.map(x => x.key -> x.combine()).toMap
}