Search code examples
scalatypeclasstype-constraints

How can I exclude a specific type from a TypeClass resolution?


I would like to provide a ToCondition operation for most types, but not for strings. (This is when porting a Javascript code, where the non-null and non-zero test is done very often and it is tedious to rewrite all such tests to proper comparison). It is easy to do this so that I receive an error runtime:

trait ToCondition[T] {
  def apply(x: T): Boolean
}
implicit object ToConditionInt extends ToCondition[Int] {
  override def apply(x: Int) = x != 0
}
implicit object ToConditionString extends ToCondition[String] {
  override def apply(x: String) = throw new UnsupportedOperationException("Cannot use String as a condition")
}
implicit object ToConditionAnyRef extends ToCondition[AnyRef] {
  override def apply(x: AnyRef) = x != null
}

def toCondition[T: ToCondition](a: T): Boolean = implicitly[ToCondition[T]].apply(a)

toCondition(1) // true

toCondition(null:AnyRef) // false

toCondition("") // throws runtime

Can this constraint be expressed somehow so that I get the error compile-time instead?


Solution

  • You could use generalized type constraint with the condition, that will never be true, like String =:= Nothing:

    implicit def ToConditionString(implicit ev: String =:= Nothing) = new ToCondition[String] {
      override def apply(x: String) = throw new UnsupportedOperationException("Cannot use String as a condition")
    }
    

    Then

    toCondition("")
    

    fails at compile time with:

    could not find implicit value for evidence parameter of type ToCondition[String]