I'm sorry for the vague or possibly incorrect question, but I'm not even sure how to state my problem in one sentence.
I have 2 traits:
trait Property[T] {
val name: String
def conformsTo(rule: Rule[T]): Boolean
}
and
trait Rule[T] {
def evaluate(valueToCheck: T): Boolean
}
I have a list of concrete classes implementing Property
and a map of Rule
implementations, where both parameterized types can either be a Double
or a String
.
When traversing this list, for each Property
instance I pass in a concrete Rule
implementation to the conformsTo
method, the compiler however errors with a type mismatch.
So in a broader sense, what I'm trying to achieve is to have a list of attributes that can be evaluated based on a given set of rules of different types, without splitting these attributes into separate lists by type.
I tried tinkering with upper/lower bounds and implicit types but ended up with nothing.
The complete code:
trait Rule[T] {
def evaluate(valueToCheck: T): Boolean
}
case class GreaterThan(value: Double) extends Rule[Double] {
override def evaluate(valueToCheck: Double): Boolean = {
valueToCheck > this.value
}
}
case class LessThan(value: Double) extends Rule[Double] {
override def evaluate(valueToCheck: Double): Boolean = {
valueToCheck < this.value
}
}
case class Is(value: String) extends Rule[String] {
override def evaluate(valueToCheck: String): Boolean = {
valueToCheck == this.value
}
}
case class isNot(value: String) extends Rule[String] {
override def evaluate(valueToCheck: String): Boolean = {
valueToCheck != this.value
}
}
trait Property[T] {
val name: String
def conformsTo(rule: Rule[T]): Boolean
}
case class DoubleProperty(name: String, value: Double) extends Property[Double] {
override def conformsTo(rule: Rule[Double]): Boolean = rule.evaluate(value)
}
case class StringProperty(name: String, value: String) extends Property[String] {
override def conformsTo(rule: Rule[String]): Boolean = rule.evaluate(value)
}
object Evaluator extends App {
val ruleMap = Map(
"name1" -> GreaterThan(123),
"name1" -> LessThan(500),
"name2" -> GreaterThan(1000),
"name3" -> Is("something"))
val numericProperty = DoubleProperty("name1", 600)
val numericProperty2 = DoubleProperty("name2", 1000)
val stringProperty = StringProperty("name3", "something")
val stringProperty2 = StringProperty("name4", "something")
val attributes = List(
numericProperty,
numericProperty2,
stringProperty,
stringProperty2)
val nonConforming = attributes
.filter(x => ruleMap.contains(x.name))
.filter(x => !x.conformsTo(ruleMap(x.name))).toList
}
the error:
type mismatch;
found : Product with Rule[_ >: String with Double] with java.io.Serializable
required: Rule[(some other)<root>._1]
Note: Any >: _1 (and Product with Rule[_ >: String with Double] with java.io.Serializable <: Rule[_ >: String with Double]), but trait Rule is invariant in type T.
You may wish to define T as -T instead. (SLS 4.5)
.filter(x => !x.conformsTo(ruleMap(x.name))).toList
Thank you for any help.