2013-07-24 9 views
6

यह अंतर्निहित वैल कैसे स्टैक ओवर फ्लोएरर का कारण बनता है?स्कैला अंतर्निहित कारण StackOverflowError

(अपने मूल कोड नीचे मुकाबले, अभी भी त्रुटि पैदा करने के लिए)

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

मैं implicits के साथ कुछ अवैध कर रहा हूं?

उत्तर

9

मुझे विश्वास है कि मैं यहां क्या हो रहा है इसका उत्तर दे सकता हूं .. यह अन्य अंतर्निहित रूपांतरणों से संबंधित है, और जिसे आपने अभी बनाया है। आप इस का पता लगाने जोड़ देते हैं तो आप पुष्टि कर सकते हैं कि क्या ढेर अतिप्रवाह आमतौर पर से संबंधित है - खुद को बार-बार कॉल जावा दुर्घटनाओं के ढेर अंतरिक्ष तक एक समारोह:

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

.... बुलाया भीतरी 4.5 भीतरी बुलाया 4.5 भीतरी बुलाया 4.5 भीतरी 4.5 बुलाया भीतरी 4.5ERROR कहा जाता है: - (या StringLike, toDouble जावा तार का एक प्राकृतिक समारोह नहीं है, बल्कि StringOps में एक अंतर्निहित रूपांतरण का उपयोग होता है java.lang.StackOverflowError

मुझे लगता है कि क्या हो रहा है यह है मुझे सच में यकीन नहीं है लेकिन यह एक ही मुद्दा है)।

तो जब आप दो बार कॉल करते हैं - संकलक एक अंतर्निहित रूपांतरण की मांग शुरू करता है जिसमें "टू डबल" फ़ंक्शन हो सकता है। सिद्धांत रूप में यह किसी भी परिणामी वर्ग हो सकता है।

लेकिन - क्या होना चाहिए यदि कई अंतर्निहित रूपांतरण इसे प्राप्त कर सकें? दुर्भाग्यवश, "डबल" में यह भी साबित होता है कि यहां सिद्ध किया गया है:

val x = 44.4 
x.toDouble 

और अनुमान लगाएं क्या? इसका मतलब है कि अब आपका नया निहित कार्य, स्कोप में निकटतम प्रतियोगिता जीतता है और "टू डबल" को पूरा करने के लिए सर्कल में बुलाया जाता है - धीरे-धीरे स्ट्रिंग को डबल में बदलने की कोशिश करता है, ताकि बार-बार (कक्षा डबल पर) कॉल किया जा सके। मैं मानता हूं कि यह काफी उलझन में है, लेकिन साक्ष्य फिट बैठता है।

यहां ठीक है .. यह स्पष्टीकरण फिट बैठता है और रिकर्सिव कॉल को रोकता है।

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

क्या किसी को पता है कि यह सबमिट करने के लायक के रूप में योग्य है या नहीं? ऐसा लगता है कि मुझे एक अंतर्निहित रूपांतरण का दायरा है, उस रूपांतरण के परिभाषित कोड के भीतर मान्य नहीं होना चाहिए। (इस प्रकार, हमेशा बाहर रखा गया)। एकमात्र परिणाम जो कभी भी इसे अनुमति देने के लिए आ सकता है, हमेशा एक अनंत लूप होगा – LaloInDublin

+0

मैंने एक मौका लिया कि यह संबोधित करने और इस मुद्दे को प्रस्तुत करने के लायक हो सकता है .. स्कैला प्रोग्रामिंग भाषा/एसआई -7693 – LaloInDublin

+0

मुझे लगता है कि स्कैला कहना ज्यादा उचित है ऐसा करने के लिए कहा गया था (यानी एक बग नहीं)। समस्या जमा करने के लिए अच्छा है और देखें कि क्या होता है। शायद उपयोगकर्ता को पहचानने और चेतावनी देने का एक चालाक तरीका है। लेकिन, समस्या यह है कि रिकर्सन से पहले कोड की कोई मात्रा और जटिलता हो सकती है। इसके अलावा, शायद कोई उस रिकर्सन चाहता था और बाहर निकलने की स्थिति को कोडित कर दिया हो। – Core

संबंधित मुद्दे