Why does this simple implicit stringToInt function cause a stack overflow?

Viewed 233

If I define a simple stringToInt function and store it as a val, everything works as expected, e.g.

scala> def stringToInt1: (String => Int) = _.toInt
stringToInt1: String => Int

scala> stringToInt1("1")
res0: Int = 1

However, if I then make that implicit, it causes a stack overflow:

scala> implicit def stringToInt2: (String => Int) = _.toInt
stringToInt2: String => Int

scala> stringToInt2("1")
java.lang.StackOverflowError
at .stringToInt2(<console>:7)
at $anonfun$stringToInt2$1.apply(<console>:7)
at $anonfun$stringToInt2$1.apply(<console>:7)
...

At first I suspected that this was because the underscore wasn't resolving to what I expected, but that's not the case, as this style of implicit val works fine for the following simple function:

scala> implicit def plusTwo: (Int => Int) = _ + 2
plusTwo: Int => Int

scala> plusTwo(2)
res2: Int = 4

If I define the parameter explicitly, no stack overflow:

scala> implicit def stringToInt3(s: String) = s.toInt
stringToInt3: (s: String)Int

scala> stringToInt3("1")
res3: Int = 1

(If trying this yourself and this last case stack overflows, restart the scala console and redo this last step)

So my question is, why is the original implicit not correctly resolving?

Edit

Ok digging a little deeper here, it seems that the problem is with the implicit conversion from String to StringOps. If we cut that out, it works fine:

scala> import scala.collection.immutable.StringOps
import scala.collection.immutable.StringOps

scala> implicit def stringToInt4: (String => Int) = new StringOps(_).toInt
stringToInt4: String => Int

scala> stringToInt4("1")
res4: Int = 1

But why would that implicit conversion be causing the issue?

2 Answers
Related