2010-11-28 19 views
5

मुझे ओवरलोडिंग के तरीकों के भिन्नता को समझने में थोड़ी सी समस्या हो रही है।स्कैला फ़ंक्शन वेरिएंस और ओवरराइडिंग

हालांकि यह पूरी तरह से वापसी प्रकार

class Bla 
class Fasel extends Bla 

trait Test[A] { 
def tester(): Bla = new Bla 
} 

class FooTest[A](a: A) extends Test[A] { 
override def tester(): Fasel = new Fasel          
} 

में सहप्रसरण की वजह से काम करता है यह एक विफल रहता है, भले ही काम करता है उनके पैरामीटर प्रकार में contravariant हैं।

class Bla 
class Fasel extends Bla 

trait Test[A] { 
def tester(a: Fasel): Bla = new Bla           
} 

class FooTest[A](a: A) extends Test[A] { 
override def tester(a: Bla): Fasel = new Fasel 
} 

मुझे यहां क्या गलत हो रहा है? कोई संकेतक?

सादर, raichoo

उत्तर

11

दो चीजें यहाँ पर जा रहे हैं:

  1. एक समारोह और एक विधि are not the same thing
  2. तरीके अपने मापदंडों 'प्रकार में बहुरूपी नहीं हैं

आपका tester विधि एक विधि है , Function1 नहीं। यह अंडरस्कोर सिंटैक्स का उपयोग एक समारोह में उठाया जा सकता है:

val f = (new FooTest[String]).tester _ // Fasel => Bla 

यह समारोह अपने इनपुट प्रकार में विपरीत संस्करण होगा। (हालांकि, यह कहने लायक है कि को पैरामीटरकृत नहीं किया जा सकता है और यह भी कहने योग्य है कि Foo या FooTest का उदाहरण tester विधि के लिए फ़ंक्शन ऑब्जेक्ट प्राप्त करने के लिए था। यह निश्चित रूप से पहले अवलोकन से होता है!)

एक फ़ंक्शन एक ऑब्जेक्ट है, इसे ओवरराइड नहीं किया जा सकता है क्योंकि इसका कोई मतलब नहीं है। तरीके ओवरराइड किया जा सकता है। हालांकि, जैसा कि मैंने उपरोक्त कहा है, ओवरराइडिंग विधि के पैरामीटर प्रकारों में बहुलक नहीं है। उदाहरण के लिए:

class A { 
    def foo(a : Any) = println("A: " + a) 
} 

class B extends A { 
    override def foo(s : String) = println("B " + s) //will not compile! 
} 

दो मेरी उदाहरण में तरीकों से ऊपर दो अलग-अलग तरीके हैं: गतिशील प्रेषण केवल विधि लक्ष्य (अर्थात वस्तु जिस पर यह कहा जा रहा है) पर काम करता है।

उपरोक्त में, उदाहरण के लिए, यदि आप override घोषणा को हटाते हैं, तो कोड संकलित होगा। आप निम्नलिखित चलाते हैं:

(new B).foo(1) //prints A 1 
(new B).foo("s") //prints B s 

ऐसा इसलिए, क्योंकि हालांकि दोनों तरीकों foo कहा जाता है, वे पूरी तरह से अलग अलग तरीकों ( अर्थात मैं अतिभारित है foo, नहीं अधिरोहित यह) कर रहे हैं।यह सबसे अच्छा माना जाता है कि एक विधि के तर्क '(उनके प्रकार सहित) उस विधि के अद्वितीय नाम का हिस्सा हैं। एक विधि केवल तभी ओवरराइड करती है जब उनके पास बिल्कुल नाम है।


अनिवार्य रूप से आप भ्रमित हो रहे हैं दो अलग और संयुक्त राष्ट्र से संबंधित आपका प्रश्न चीजें हैं जो मैं स्पष्टता के लिए नीचे रख देगा:

  • Function1 पर विचरण एनोटेशन को परिभाषित क्या यह के लिए इसका मतलब एक फ़ंक्शन किसी अन्य प्रकार का संदर्भ (और इसलिए असाइन किए गए किसी दिए गए प्रकार के संदर्भ में)।
  • उप-वर्गों पर विधियों को ओवरराइड किया जा सकता है और भाषा विनिर्देश इस तरह के ओवरराइडिंग के लिए नियमों की रूपरेखा तैयार करता है।
+0

स्कैला संदर्भ में मैं इसे कहां पढ़ सकता हूं? बस पूर्णता के लिए :) – raichoo

+2

समझ गया: 3.3.1 विधि प्रकार धन्यवाद :) – raichoo

+1

मैंने विधि/फ़ंक्शन तुलना पर एक SO प्रश्न का एक लिंक जोड़ा है। साथ ही, विधि ओवरराइडिंग के बारे में बिट बाइटकोड की परिभाषा का हिस्सा है (यानी क्लास फ़ाइल प्रारूप spec)। हालांकि मुझे लगता है कि स्कैला भाषा का विवरण बताता है कि बाइटकोड विधि में स्कैला विधि "उठाया" कैसे है। –

-1

खैर अपने दूसरे उदाहरण में Test में tester() के हस्ताक्षर एक Fasel तर्क वाणी लेकिन FooTesttester() की ओवरराइड हस्ताक्षर के साथ तर्क के रूप में एक Bla साथ घोषित किया जाता है। चूंकि FaselBla का उप-प्रकार है extend एस पदानुक्रम द्वारा यह संभवतः गलत है।

+0

आप बिंदु खो रहे हैं। एक फ़ंक्शन इसके इनपुट पैरामीटर में कॉन्ट्रैक्ट-वेरिएंट है। इसलिए ओपी विधि ओवरराइडिंग और फ़ंक्शन भिन्नता के बीच अंतर के बारे में उलझन में था –

0

आप ओवरराइड कर सकते हैं और एक उप-प्रकार के लिए वापसी प्रकार बदलने के लिए, लेकिन जब तर्क के लिए महाप्रकार को स्वीकार प्रतिस्थापन सिद्धांत को संतुष्ट होता है, यह अनुमति नहीं है (यह सिर्फ जावा में के रूप में है) कारण है कि आप भी कर सकते हैं अधिभार विधियों (एक ही नाम के साथ कई विधियों, विभिन्न तर्क गिनती और प्रकार) और आपकी विधि को अधिभारित किया जाएगा। मुझे लगता है कि यह मुख्य रूप से जेवीएम संगतता का सवाल है और उचित नमूना है। ओवरलोडिंग पहले से ही स्केल स्पेक को जटिल बनाती है। सीधे शब्दों में अतिभारित एक बदल हस्ताक्षर के साथ करने के लिए ओवरराइड विधि मार्ग काफी अच्छा हो सकता है:

class FooTest[A] extends Test[A] { 
    override def test(a: Fasel) : Fasel = test(a.asInstanceOf[Bla]) 
    def test(a: Bla) : Fasel = new Fasel 
} 

आप क्या कर सकते हैं, एक प्रकार पैरामीटर contravariant, में प्रदान की जाती है (केवल contravariant स्थान पर दिखाई देता सरल बनाने बनाने के तर्क प्रकार के रूप में प्रकट होता है और परिणाम प्रकार के रूप में नहीं), लेकिन यह काफी अलग है:

trait Test[-A] { 
    // note the - before A. 
    // You might want to constraint with -A >: Fasel 
    def tester(a: A) : Bla = new Bla 
} 

class FooTest extends Test[Bla] { 
    override def tester(a: Bla): Fasel = new Fasel 
} 

val testOfBla: Test[Bla] = new FooTest 
val testOfFasel: Test[Fasel] = testOfBla 
    // you can assign a Test[Bla] to a test[Fasel] because of the -A 
4

कल्पना के संगत के टुकड़े:

विधि प्रकार

एक विधि प्रकार (Ps)U, जहां (Ps) पैरामीटर नाम और प्रकार कुछ n≥0 और U के लिए (p1 :T1,...,pn :Tn) का क्रम है के रूप में आंतरिक रूप से प्रदर्शित किया जाता है एक (मूल्य या विधि) प्रकार है। इस प्रकार नामित विधियों का प्रतिनिधित्व करता है जो p1, ..., pn नाम T1,...,Tn के तर्क लेते हैं और यह U प्रकार का परिणाम लौटाते हैं।

विधि प्रकार मूल्यों के प्रकार के रूप में मौजूद नहीं हैं। यदि किसी विधि का नाम किसी मान के रूप में उपयोग किया जाता है, तो इसका प्रकार निहित रूप से संबंधित फ़ंक्शन प्रकार (§6.26) में परिवर्तित हो जाता है।

ओवरराइड

एक सदस्य मैचों (§5.1.3) एक गैर निजी सदस्य C का एक आधार वर्ग के M′ कि सदस्य ओवरराइड करने के लिए कहा जाता है कि वर्ग C की M कि। इस मामले में ओवरराइडिंग सदस्य M के बाध्यकारी को उपरोक्त के बाध्यकारी (§3.5.2) को सब्सक्राइब करना चाहिए।

अनुरूपता

तो i = 1, ..., n के लिए Ti ≡ Ti′ और U को U′ तो विधि प्रकार (p1 : T1,...,pn :Tn)U(p1′ :T1′,...,pn′ :Tn′)U′ के अनुरूप अनुरूप है।

एक घोषणा या परिभाषा वर्ग प्रकार C के कुछ यौगिक प्रकार में कुछ यौगिक प्रकार या वर्ग प्रकार C′ में इसी नाम के एक और घोषणा subsumes, अगर निम्न में से एक मानती है subsumes।

  • मान घोषणा या परिभाषा है कि प्रकार टी के साथ एक नाम एक्स को परिभाषित करता है एक मूल्य या विधि घोषणा उस प्रकार T′ साथ x को परिभाषित करता है subsumes, T <: T′ प्रदान की है।