It is an ambiguous implicit value, the only way we want to make a mistake that existed at compile time

trait Foo

trait Bar extends Foo

def doStuff[T <: Foo](x: T)(implicit ev: T =!:= Foo) = x

doStuff(new Foo{}) //ambiguous implicit value
doStuff(new Bar)// successful

Implicit resolution occurs at compile time, so here I think there may be two implicit values ​​with exactly the same type to cause ambiguous material.

Right now, I'm going to introduce the formless into the team, my colleagues believe that this ambiguous implicit is not perfect, and I have no good reason. This is the only way to do this to make the type safe in scala. If so, what can I do to customize the error message?

Edit:

In formless, I want to make the sum of 2 NATs not equal to 7, I can make the code in such a way as to compile the compilation.

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)

, ?

+4
3

, ( ) .

, Foo , Bar ( ) , Foo. , doStuff. Scala @implicitNotFound, , .

@annotation.implicitNotFound(msg = "No Props instance for ${T}")
trait Props[T] {
  def wibble(t: T): Double
}

trait Foo
// Note no Props instance for Foo ...

trait Bar extends Foo
object Bar {
  // Props instance for Bar
  implicit def barProps: Props[Bar] = new Props[Bar] {
    def wibble(t: Bar): Double = 23.0
  }
}

def doStuff[T <: Foo](t: T)(implicit props: Props[T]) = props.wibble(t)

scala> doStuff(new Foo {})
<console>:11: error: No Props instance for Foo
              doStuff(new Foo {})
                     ^

scala> doStuff(new Bar {})
res1: Double = 23.0

, Foo Bar, , Foo doStuff.

, , =!:= ( Scala own =:=) , .

+7

, : fooobar.com/questions/1508/...

:

@annotation.implicitNotFound(msg = "Cannot prove that ${A} =!= ${B}.")
trait =!=[A,B]
object =!= {
  class Impl[A, B]
  object Impl {
    implicit def neq[A, B] : A Impl B = null
    implicit def neqAmbig1[A] : A Impl A = null
    implicit def neqAmbig2[A] : A Impl A = null
  }

  implicit def foo[A,B]( implicit e: A Impl B ): A =!= B = null
}

error: Cannot prove that Foo =!= Foo:

def doStuff[T <: Foo](x: T)(implicit ev: T =!= Foo) = x
doStuff(new Foo{}) // error: Cannot prove that Foo =!= Foo
doStuff(new Bar)// successful
+4

Another way you can set a restriction on your method doStuffis to use a magnet template, which is just an extended type class, for example:

trait Foo
trait Bar

object DoStuff {
  def doStuff[T](value: StuffMagnet[T]): Unit = value()
}

trait StuffMagnet[T] {
  def apply(): Unit
}

object StuffMagnet {
  implicit def forFoo(foo: Foo): StuffMagnet[Foo] = 
    new StuffMagnet[Foo] {
      def apply(): Unit = ()
    }
}

The difference in this case would be that you cannot add an implicitNotFound annotation for a better compile-time error message, you will get a simple type mismatch, for example:

Test.scala:20: error: type mismatch;
 found   : Test.Bar
 required: Test.StuffMagnet[?]
  DoStuff.doStuff(new Bar {})
                  ^
one error found
0
source

All Articles