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 Double
s, not String
s. But I did tell you how to go from String
s to Double
s, 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
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 forDouble
s, notString
s. But I did tell you how to go fromString
s toDouble
s, 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 doingstrToDouble("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