2013-07-24 13 views
6

In che modo questa valenza implicita causa uno StackOverFlowError?cause implicite scala StackOverflowError

(abita in fondo il mio codice originale, per causare ancora l'errore)

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

sto facendo qualcosa di illegale con impliciti?

risposta

9

Credo di poter rispondere a quello che sta succedendo qui .. è correlato ad altre conversioni implicite e a quella che hai appena creato. Se si aggiunge questo tracciato è possibile confermare ciò overflow dello stack di solito si riferisce a - una funzione che si fa chiamare ripetutamente fino a quando lo spazio pila di crash Java:

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

.... chiamato interna 4,5 chiamata interna 4,5 chiamata interna 4,5 chiamato interna 4,5 chiamato 4.5ERROR interno: java.lang.StackOverFlowError

Penso che quello che sta accadendo è questo - toDouble non è una funzione naturale della stringa java, ma piuttosto avviene utilizzando una conversione implicita in StringOps (o a corda, Non sono molto sicuro, ma è lo stesso problema).

Quindi, quando si chiama Double, il compilatore inizia a cercare una conversione implicita che potrebbe contenere la funzione "toDouble". In teoria potrebbe essere una qualsiasi classe risultante.

MA - cosa dovrebbe accadere se diverse conversioni implicite potrebbero raggiungere questo obiettivo? Purtroppo, "Double" contiene anche la funzione toDouble come dimostrato qui:

val x = 44.4 
x.toDouble 

E indovinate un po '? Ciò significa che la tua nuova funzione implicita, ora più vicina allo scope, vince la gara e viene chiamata in un cerchio per eseguire "toDouble", tentando in pratica di trasformare la stringa in una doppia, per chiamare ripetutamente Double (nella classe Double). Ammetto che è abbastanza confuso, ma le prove si adattano.

Ecco la correzione .. si adatta alla spiegazione e impedisce le chiamate ricorsive.

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

Qualcuno sa se questo si qualifica come un bug che vale la pena presentare? Mi sembra lo scopo di una conversione implicita, non dovrebbe essere valido all'interno del codice che definisce questa conversione. (quindi, sempre escluso). L'unico risultato che è mai stato possibile ottenere, sarebbe sempre un ciclo infinito – LaloInDublin

+0

Ho colto l'occasione che potrebbe valere la pena di affrontare e presentare il problema .. Scala Programming Language/SI-7693 – LaloInDublin

+0

Penso che sia più giusto dire Scala ha fatto esattamente quello che è stato chiesto di fare (cioè non un bug). Buono a presentare il problema e vedere cosa succede. Forse c'è un modo intelligente per rilevare e avvisare l'utente. Ma il problema è che potrebbero esserci quantità e complessità di codice prima della ricorsione. Inoltre, forse qualcuno voleva quella ricorsione e ha codificato una condizione di uscita. – Core

Problemi correlati