4
def typeSafeSum[T <: Nat, W <: Nat, R <: Nat](x: T, y: W)
         (implicit sum: Sum.Aux[T, W, R], error: R =:!= _7) = x

typeSafeSum(_3, _4) //compilation error, ambiguous implicit found.

I dont think that error message "ambiguous implicit found" is friendly, how can I customize it to say something like "the sum of 2 NAT value should not equal to 7"

Many thanks in advance

Miles Sabin
  • 23,015
  • 6
  • 61
  • 95
Xiaohe Dong
  • 4,953
  • 6
  • 24
  • 53
  • possible duplicate of [Is ambiguous implicit value the only way we want to make the error existed in compilation time](http://stackoverflow.com/questions/24926521/is-ambiguous-implicit-value-the-only-way-we-want-to-make-the-error-existed-in-co) – Sean Vieira Jul 29 '14 at 01:40
  • not really, I asked that question, implicit not found annotation is not same as ambiguous implicit found exception – Xiaohe Dong Jul 29 '14 at 04:37

1 Answers1

8

shapeless's =:!= (and similar type inequality operators) inherently exploit ambiguous implicits to encode Prolog-style negation as failure. And, as you've observed, Scala doesn't have a mechanism which allows library authors to provide more meaningful error messages when ambiguity is expected. Perhaps it should, or perhaps Scala should provide a more direct representation of the negation of a type making this encoding unnecessary.

Given that you've couched the question in terms of Nats I think it's probably reasonable that you're trying to work with type inequality. If it weren't Nats my recommendation in answer to another question that a type class directly encoding the relation of interest would apply here too. As it is though, I recommend that same solution as a workaround for not being able to provide better error messages.

import shapeless._, nat._, ops.nat._

@annotation.implicitNotFound(msg = "${A} + ${B} = ${N}")
trait SumNotN[A <: Nat, B <: Nat, N <: Nat]
object SumNotN {
  implicit def sumNotN[A <: Nat, B <: Nat, R <: Nat, N <: Nat]
    (implicit sum: Sum.Aux[A, B, R], error: R =:!= N): SumNotN[A, B, N] =
      new SumNotN[A, B, N] {}     
}

def typeSafeSum[T <: Nat, W <: Nat](x: T, y: W)
  (implicit valid: SumNotN[T, W, _7]) = x

scala> typeSafeSum(_3, _4)
<console>:20: error: shapeless.nat._3 + shapeless.nat._4 = shapeless.nat._7
              typeSafeSum(_3, _4)
                         ^

The technique (hiding an expected ambiguous implicit behind an implicit we expect to be not found in the case of underlying ambiguity) is generally applicable, but is obviously fairly heavyweight ... another reason why type inequalities should be avoided if at all possible.

Community
  • 1
  • 1
Miles Sabin
  • 23,015
  • 6
  • 61
  • 95
  • Thanks for your answer, I agree this is still fairly heavy.... Maybe we should have ambiguousNotFound annotation for new Scala version :) – Xiaohe Dong Jul 30 '14 at 13:31