2013-07-24 14 views
6

Wie verursacht dieses implizite val einen StackOverFlowError?skalare implizite Ursachen StackOverflowError

(verglichen meinen ursprünglichen Code unten, um noch den Fehler zu verursachen)

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"))) 
    } 
} 

Bin ich etwas Illegales mit implicits tun?

Antwort

9

Ich glaube, ich kann beantworten, was hier passiert .. ist es auf andere implizite Konvertierungen im Zusammenhang, und die, die Sie gerade erstellt haben. Wenn Sie diese Spur hinzufügen können Sie bestätigen, was Stack-Überlauf in der Regel bezieht sich auf - eine Funktion selbst so oft, bis der Stapelspeicher von Java-Abstürze Aufruf:

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

.... genannt Innen 4.5 genannt Innen 4,5 genannt Innen 4,5 Innen 4,5 genannt innerer 4.5ERROR genannt: java.lang.StackOverflowError

denke ich, was passiert, ist dies - ToDouble keine natürliche Funktion von Java-String, sondern geschieht eine implizite Konvertierung in StringOps (oder schnur, Ich bin nicht wirklich sicher, aber es ist das gleiche Problem).

Also, wenn Sie anrufen ToDouble - der Compiler eine implizite Konvertierung beginnt suchen, die die Funktion „ToDouble“ enthalten könnte. In der Theorie könnte es jede resultierende Klasse sein.

ABER - was sollte passieren, wenn mehrere implizite Konvertierungen dies erreichen könnten? Leider enthält "Double" auch die Funktion toDouble wie hier bewiesen:

val x = 44.4 
x.toDouble 

Und raten Sie mal was? Das bedeutet, dass Ihre neue implizite Funktion, die jetzt am nächsten ist, den Wettbewerb gewinnt und in einem Kreis aufgerufen wird, um "toDouble" zu erreichen - effektiv versucht, die Zeichenkette in ein Double umzuwandeln, um double (in der Klasse Double) wiederholt aufzurufen. Ich gebe zu, es ist ziemlich verwirrend, aber die Beweise passen.

Hier ist der Fix .. es passt die Erklärung und verhindert die rekursiven Aufrufe.

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

Weiß jemand, ob dies ein Fehler ist, der sich zu übermitteln lohnt? Es scheint mir der Umfang einer impliziten Konvertierung, sollte nicht innerhalb der definierenden Code dieser Konvertierung gültig sein. (also immer ausgeschlossen). Das einzige Ergebnis, das jemals daraus hervorgehen könnte, wäre immer eine Endlosschleife. – LaloInDublin

+0

Ich nahm eine Chance wahr, dass es sich lohnen könnte, das Problem anzugehen und einzureichen. Scala Programmiersprache/SI-7693 – LaloInDublin

+0

Ich denke, es ist fairer, Scala zu sagen tat genau das, wozu man es gebeten hatte (also kein Bug). Es ist gut, das Problem einzureichen und zu sehen, was passiert. Vielleicht gibt es eine clevere Möglichkeit, den Benutzer zu erkennen und zu warnen. Aber das Problem ist, dass es vor der Rekursion eine Menge und Komplexität des Codes geben könnte. Vielleicht wollte jemand diese Rekursion und hat eine Ausgangsbedingung codiert. – Core

Verwandte Themen