Search code examples
scalacompiler-errorsimplicit

Scala implicit implicit


I'm trying to do some implicit magic in my code but the issue is very simple and I have extracted it out here. It seems a bit strange since from what I've read the following should work.

   implicit class Foo(value: Double) {
      def twice = 2*value
    }

    2.0.twice

    implicit def strToDouble(x: String) = Try(x.toDouble) match {
      case Success(d) => d
      case Failure(_) => 0.0
    }

    strToDouble("2.0").twice
    val a: Double = "2.0"
    val b: Double = "equals 0.0"
    "2.0".twice 
    

I get a compile error

 value twice is not a member of String
[error]     "2.0".twice

I get you compiler, twice is defined for Doubles, not Strings. But I did tell you how to go from Strings to Doubles, and there is no ambiguity here (as far as I can tell), so shouldn't you be able to note that "2.0".twice can be done by doing strToDouble("2.0").twice?

Am I missing something here? Or is this an optimisation so that the compiler doesn't try out all the possible permutations of implicits (which would grow super-exponentially, I think as a factorial). I suppose I'm looking for a confirmation or rejection of this really.

Thanks


Solution

  • If you want extension method to be applicable even after implicit conversion, you can fix the definition of implicit class

    implicit class Foo[A](value: A)(implicit ev: A => Double) {
      def twice: Double = 2 * value
    }
    
    implicit def strToDouble(x: String): Double = ???
    
    2.0.twice   //compiles
    "2.0".twice //compiles
    

    I get you compiler, twice is defined for Doubles, not Strings. But I did tell you how to go from Strings to Doubles, and there is no ambiguity here (as far as I can tell), so shouldn't you be able to note that "2.0".twice can be done by doing strToDouble("2.0").twice?

    According to specification implicit conversions are applicable in three cases only

    Why can't the compiler select the correct String.contains method when using this lambda shorthand?

    https://scala-lang.org/files/archive/spec/2.13/07-implicits.html#views

    The conversion of 2.0.twice to Foo(2.0).twice is the 2nd case and the conversion of "2.0" to strToDouble("2.0") is the 1st case. As you can see there is no item that they can be applied together. So if you want them to be applicable together you should specify that explicitly like I showed above.

    Similarly if you defined conversions from A to B and from B to C this doesn't mean you have a conversion from A to C

    case class A(i: Int)
    case class B(i: Int)
    case class C(i: Int)
    implicit def aToB(a: A): B = B(a.i)
    implicit def bToC(b: B): C = C(b.i)
    
    A(1): B    // compiles
    B(1): C    // compiles
    // A(1): C //doesn't compile