Scala implicit reasons StackOverflowError

How does this implicit val raise a StackOverFlowError?

(compared to my source code to still throw an error)

object Complicit { // a class with name, default, and conversion function as implicit val case class CC[A](name: String, defaultValue: A)(implicit val convert: String => A) { def getFrom(s: String): A= try { convert(s) } catch { case t: Throwable => println("ERROR: %s".format(t)) // just to see the StackOverflowException defaultValue } } // this works fine object Works { val cc1= CC("first", 0.1)(_.toDouble) } // this causes java.lang.StackOverflowError due to the implicit object Fails { // !!! StackOverFlowError here implicit val stringToDouble: String => Double= { _.toDouble } val cc2= CC("second", 0.2) } def main(args: Array[String]) { // this works println("%s %f".format(Works.cc1.name, Works.cc1.getFrom("2.3"))) // this fails println("%s %f".format(Fails.cc2.name, Fails.cc2.getFrom("4.5"))) } } 

Am I doing something illegal with implications?

+6
source share
1 answer

I believe that I can answer what is happening here. This is due to other implicit conversions and what you just created. If you add this trace, you can confirm that the stack overflow usually refers to - a function that calls itself repeatedly until the java stack space falls:

 implicit val stringsToDouble: String => Double= { x=>println("called inner "+x); x.toDouble } 

.... internal 4.5 internal 4.5 internal 4.5 internal 4.5 internal 4.5ERROR: java.lang.StackOverflowError

I think this happens - toDouble is not a natural function of the java string, but rather happens using an implicit conversion to StringOps (or StringLike, I'm not sure, but this is the same problem).

So, when you call toDouble, the compiler starts looking for an implicit conversion that may contain the "toDouble" function. Theoretically, this could be any resulting class.

BUT - what should happen if it can do several implicit conversions? Unfortunately, "Double" also contains the toDouble function, as proven here:

 val x = 44.4 x.toDouble 

And guess what? This means that your new implicit function, the one closest in scope, wins the competition and gets a call in the circle to execute "toDouble" - effectively trying to turn the string into a double to repeatedly call toDouble (in the Double class). I admit this is rather confusing, but the proof is right.

Here's the fix .. it comes up with an explanation and prevents recursive calls.

  implicit val stringsToDouble: String => Double= { java.lang.Double.parseDouble(_) } 
+9
source

Source: https://habr.com/ru/post/950145/


All Articles