Why did these implicit conversions lead to code coding

Consider the following code in Scala:

object Test { class A {} class B extends A {} class AI extends A { def sayHello: String = "Hello from AI" } implicit def AtoAI(a: A): AI = a class BI extends B { def sayHello: String = "Hello from BI" } implicit def BtoBI(b: B): BI = b def main(args: Array[String]) { val a = new A println(a.sayHello) val b = new B println(b.sayHello) } } 

Using implicits leads to a coding cycle. In fact, the showdowns show that the conversion methods created have only goto 0 inside:

 public Test$AI AtoAI(Test$A); Code: 0: goto 0 public Test$BI BtoBI(Test$B); Code: 0: goto 0 

What causes this behavior? I understand that the class hierarchy here is suspect, but the implicit conversion should only be applied once.

I am using Scala 2.9.1

+7
source share
2 answers

Not bad, but I would definitely not call it a mistake.

It comes down to

 class A class B implicit def aToB(a: A) : B = a 

There is no need for both sides of the transformation to be connected in any way. Implicit is the same as writing

 implicit def aToB(a: A): B = aToB(a) 

because the compiler inserts a call to aToB to convert the result of a to the desired return type B

The goto 0 implementation is just tail call optimization. Perhaps the compiler generates a warning when it generates a method that starts in this way.

Maybe, it may be the rule that implicit methods are not available as implicit within your own body. But it does not always create an endless loop

 implicit def listAToListB(l: list[A] = l match { case Nil => Nil case x:xs => toB(x) :: xs // equivalent to toB(x) :: listAToList[B](xs) } 

(ok is just a map(toB) ). In any case, the same thing can happen with two mutually recursive implications. In my opinion, you should not configure the specification in order to avoid the possibility of writing an endless chain of "do nothing", among many others. But a warning when such a cycle is detected, regardless of implications, will be pleasant.

+12
source

I cannot understand why the code compiles at all. I checked that it compiles. Wouldn't you have to omit the implicit conversion method inside?

Didier points out that implicit conversion is applied recursively, which means that code can be compiled without downgrading.

The following code adds downcasts (which should not change runtime behavior). It does not work at runtime with unsuccessful drops. So this seems like a compiler error. As Didier says, explicit devastation prevents a recursive application of implicit conversion here.

 object Test { class A {} class B extends A {} class AI extends A { def sayHello: String = "Hello from AI" } implicit def AtoAI(a: A): AI = a.asInstanceOf[AI] class BI extends B { def sayHello: String = "Hello from BI" } implicit def BtoBI(b: B): BI = b.asInstanceOf[BI] def main(args: Array[String]) { val a = new A println(a.sayHello) val b = new B println(b.sayHello) } } 

Closing up, answering the question: you call the AI method for an object of class A that does not have this method. Obviously this will not work. What is happening is not indicated; in your case it was an endless cycle.

+2
source

All Articles