2012-01-13 13 views
7

पाशन स्काला में निम्न कोड पर विचार करें में हुई:क्यों इन निहित रूपांतरण कोड

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

कोड पाशन में implicits परिणामों के उपयोग। वास्तव में, disassemblying का पता चलता है, उत्पन्न कि रूपांतरण तरीकों केवल एक goto 0 अंदर है:

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

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

क्या है कि व्यवहार का कारण बनता है? मैं समझता हूं कि यहां कक्षाओं का पदानुक्रम एक संदिग्ध है, लेकिन निहित रूपांतरण केवल एक बार लागू किया जाना चाहिए।

मैं स्काला 2.9.1

+2

मुझे समझ में नहीं आ रहा है कि कोड बिल्कुल क्यों संकलित करता है (मैंने सत्यापित किया है कि यह * संकलित करता है)। क्या आपको अंतर्निहित रूपांतरण विधि के अंदर डाउनकास्ट नहीं करना पड़ेगा? – ziggystar

+0

असल में, मैं न तो। यह कोड के एक बड़े हिस्से से अलग मामला है। –

उत्तर

12

अच्छा नहीं है लेकिन मैं निश्चित रूप से इसे एक बग नहीं कहूंगा।

यह

class A 

class B 

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

करने पर निर्भर करता रूपांतरण के दो पहलू की कोई आवश्यकता नहीं किसी भी तरह से संबंधित होने के लिए नहीं है। अंतर्निहित

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

लिख क्योंकि संकलक आदेश की आवश्यकता वापसी प्रकार B लिए परिणाम a कन्वर्ट करने के लिए में aToB कॉल सम्मिलित करता है के रूप में सिर्फ एक ही बात है।

goto 0 कार्यान्वयन केवल एक पूंछ कॉल अनुकूलन है। संकलक शायद एक चेतावनी देता है जब यह एक तरीका उत्पन्न करता है जो इस तरह से शुरू होता है।

शायद एक नियम हो सकता है कि अंतर्निहित विधियां अपने शरीर के अंदर प्रत्यारोपण के रूप में उपलब्ध नहीं हैं। लेकिन यह हमेशा एक अनंत लूप

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

(ठीक यह सिर्फ एक map(toB) है) नहीं बनाता है। वैसे भी दो पारस्परिक रूप से पुनरावर्ती implicits के साथ ऐसा ही हो सकता है। मेरी राय में, अनंत को लिखने की कुछ संभावनाओं से बचने के लिए, कई अन्य लोगों के बीच कुछ भी लूप न करने के लिए कल्पना को ट्विक करना उचित नहीं है। लेकिन एक चेतावनी जब इस तरह के एक पाश का पता चला है, भले ही implicits, अच्छा होगा।

+0

अच्छा जवाब! ओ/सीयू – ron

+0

उत्तर के लिए धन्यवाद! –

2

का उपयोग मैं नहीं समझ सकता क्यों कोड बिल्कुल संकलित करता है। मैंने सत्यापित किया कि यह संकलित करता है। क्या आपको अंतर्निहित रूपांतरण विधि के अंदर डाउनकास्ट नहीं करना पड़ेगा?

डिडिएर बताते हैं कि निहित रूपांतरण दोबारा लागू होता है, जिसका अर्थ है कि कोड डाउनकास्ट के बिना संकलित हो सकता है।

निम्नलिखित कोड डाउनकास्ट जोड़ता है (जो रनटाइम व्यवहार को नहीं बदला जाना चाहिए)। यह असफल होने के साथ रनटाइम पर विफल रहता है। तो यह मेरे लिए एक कंपाइलर बग की तरह दिखता है। जैसा कि डिडिएर कहते हैं, स्पष्ट डाउनकास्ट यहां अंतर्निहित रूपांतरण के पुनरावर्ती अनुप्रयोग को रोकता है।

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

फिनिशिंग प्रश्न का उत्तर देकर: आप वर्ग A का एक उद्देश्य है कि इस विधि नहीं है पर AI की एक विधि कहते हैं। जाहिर है यह काम नहीं कर सकता है। क्या होता है निर्दिष्ट नहीं है; आपके मामले में यह एक अनंत लूप था।

+1

एक (असफल) डाउनकास्ट जोड़ना व्यवहार को बदलता है, क्योंकि डाउनकास्ट के साथ, कंपाइलर एक निहित रूपांतरण डालने का प्रयास नहीं करेगा। –

+0

उत्तर के लिए धन्यवाद! –

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