2010-07-04 11 views
6

मेरे पास एक बेस क्लास है जो जावा लाइब्रेरी से आता है, जिसका कोड मैं संशोधित नहीं कर सकता।एक विशेषता, असंगत संकलक व्यवहार के साथ एक अमूर्त विधि को लागू करना?

class A { 
    def b { } 
} 

मैं स्काला में इस वर्ग का विस्तार करने और यह अमूर्त बनाने के लिए विधि ओवरराइड:: इस वर्ग (ए) एक खाली विधि (ख) जो बजाय सार के रूप में घोषित किया जाना चाहिए था है

abstract class AA extends A { 
    override def b 
} 

trait B { 
    def b { println("B") } 
} 

अगर मैं विशेषता बी के साथ ए.ए. का विस्तार, मैं एक त्रुटि मिलती है: अब मैं एक विशेषता में इस विधि को लागू प्रकार => यूनिट के वर्ग ए में अधिभावी विधि ख; प्रकार के लक्षण बी में विधि ख => यूनिट की जरूरत है `ओवरराइड 'संशोधक:

class C extends AA with B {} 

इसके बजाय, यदि कोड इस तरह से किया गया था, सब कुछ त्रुटियों के बिना जो थोड़ा मेरे लिए विरोधाभासी लगता है संकलित किया गया है,:

abstract class AA { 
    def b 
} 

trait B { 
    def b { println("B") } 
} 

class C extends AA with B {} 

मैं स्कैला 2.8.0 आरसी 3 चला रहा हूं, और पूरी तरह से भाषा (3 दिन) के लिए नया हूं। एक और अजीब और संबंधित व्यवहार है कि ओवरराइड लेबल आवश्यक जब ख सार नहीं है:

abstract class AA extends A { 
    def b 
} 
+0

क्या यह वही समस्या है जैसे आप जावा क्लास के जावा टूस्ट्रिंग कार्यान्वयन को अपने स्वयं के 'def toString(): स्ट्रिंग' कार्यान्वयन को मिश्रित करके बदलना चाहते हैं जिसे आपने एक विशेषता में परिभाषित किया होगा? – huynhjl

+0

नहीं, यह वही मामला नहीं है। उस स्थिति में संकलक व्यवहार पूरी समझ में आता है, क्योंकि यह संदिग्ध है कि परिभाषा का उपयोग किया जाना चाहिए: जावा टूस्ट्रिंग या मिश्रण एक। मेरे मामले में केवल एक ही उपलब्ध है, हालांकि। –

उत्तर

2

सुनिश्चित नहीं हैं कि अगर यह सही समाधान है, लेकिन अगर आपके trait BA फैली (और ओवरराइड b), तो सब कुछ ठीक संकलन :

C:\Users\VonC>scala 
Welcome to Scala version 2.8.0.RC5 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_18). 
Type in expressions to have them evaluated. 
Type :help for more information. 

scala> class A { 
    | def b { println("A b") } 
    | } 
defined class A 

scala> new A 
res5: A = [email protected] 

scala> res5.b 
A b 

scala> abstract class AA extends A { 
    | override def b 
    | } 
defined class AA 

तुमने किया क्या:

पहले के A और AA परिभाषित की तरह आप उन्हें अपने प्रश्न में पेश करते हैं

scala> trait B { 
    | override def b { println("B b") } 
    | } 
<console>:6: error: method b overrides nothing 
     override def b { println("B b") } 
        ^

क्या मैं विशेषता बी के साथ की कोशिश की (क्रम में जोड़ने के लिए 'override' सक्षम होने के लिए):

scala> trait B extends A { 
    | override def b { println("B b") } 
    | } 
defined trait B 

तो अब:

scala> class C extends AA with B {} 
defined class C 

scala> new C 
res7: C = [email protected] 

scala> res7.b 
B b 

सही b ओवरराइड विधि कहा जाता है C.b


अपने स्पष्ट "विसंगति" का सवाल है, Scala for Java Refugees Part 5: Traits and Types देखें:

To start with, there’s that ever-annoying override keyword. I mentioned back in the article on basic OOP that any method which overrides a method in a superclass must be declared with the override modifier. At the time, I likened it to the language mandating the use of the @Override annotation, with its primary purpose being to enforce the good practice.

The real key to the power of traits is the way in which the compiler treats them in an inheriting class.
Traits are actually mixins, not true parent classes.
Any non-abstract trait members are actually included in the inheriting class, as in physically part of the class. Well, not physically, but you get the picture.
It’s as if the compiler performs a cut-and-paste with the non-abstract members and inserts them into the inheriting class. This means that there’s no ambiguity in the inheritance path, meaning no diamond problem.

तो अपने दूसरे उदाहरण में override कीवर्ड के लिए कोई जरूरत नहीं।

+0

आपके विस्तृत उत्तर के लिए धन्यवाद। मुझे लगता है कि मैं गुणों को समझता हूं क्योंकि मैं रूबी से आया हूं, जिसमें मॉड्यूल हैं, वही बात है। आईएमएचओ बनाने का गुण बी विस्तार एक विशेषता के उद्देश्य को हराता है, क्योंकि मैं इस विशेषता का उपयोग किसी अन्य श्रेणी पदानुक्रम में नहीं कर सकता, जो ठीक है जो मैं करने की कोशिश कर रहा हूं। कोई विचार? मुझे लगता है कि समस्या स्कैला कंपाइलर में निहित है, जो यह नहीं देख रहा है कि विधि बी अमूर्त हो गई है, और पत्ती वर्ग सी –

+0

@ एआर में विशेषता में मिश्रण करते समय इसकी परिभाषा में कोई अस्पष्टता नहीं है: मैं समझता हूं; मेरा जवाब http://blog.objectmentor.com/articles/2008/09/29/a-scala-style-_with_-construct-for-ruby द्वारा प्रेरित था। अभी भी अन्य समाधानों की जांच कर रहे हैं। – VonC

5

देखने के लिए क्या हो रहा है की कोशिश करने के लिए, मैंने कोशिश की यह:

scala> class A{ 
    | def b{ } 
    | } 
defined class A 

scala> abstract class AA extends A{ 
    | override def b 
    | } 
defined class AA 

scala> class AAA extends AA{ 
    | def b = println("AAA") 
    | } 
<console>:8: error: overriding method b in class A of type => Unit; 
method b needs `override' modifier 
     def b = println("AAA") 
      ^

जाहिर है, समस्या के स्रोत सार कक्षाएं नहीं के लिए की जरूरत से अपने सुपर क्लास में तरीकों "को मुक्त" कर सकते हैं अमूर्त वर्ग के उप-वर्गों को 'ओवरराइड' संशोधक शामिल करने के लिए।

+0

ठीक है, कक्षा सी में ओवरराइड डीफ़ = सुपर [बी] .b के साथ कंपाइलर के लिए अस्पष्टता को पूर्ववत करके ओवरराइड चीज़ को आसानी से ठीक किया जा सकता है, लेकिन यह आवश्यक नहीं होना चाहिए। यही मेरा सवाल है। धन्यवाद! –

+0

एमजेपी सही है: कंक्रीट सदस्यों को हमेशा उप-वर्ग में सार नहीं बनाया जा सकता है। उप-वर्ग में एक अमूर्त सदस्य घोषणा का कोई प्रभाव नहीं पड़ता है। यह मिश्रित संरचना के नियमों का एक परिणाम है, जहां कंक्रीट हमेशा अमूर्त पर प्राथमिकता लेता है, इससे कोई फर्क नहीं पड़ता कि परिभाषाओं वाले लक्षणों का क्रम क्या है। –

2

समस्या बहुत सूक्ष्म है।अंगूठे के नियम के रूप में, आपकी कक्षा एए, जो तक फैली हुई है, को का विस्तार करने वाले लक्षणों के साथ मिश्रित किया जाना चाहिए।

आप ने क्या किया:

class A { 
    def b { } 
} 

abstract class AA extends A { 
    override def b 
} 

trait B { 
    def b { println("B") } 
} 

इसलिए जब आप ए.ए. और बी विधि दो बार परिभाषित किया गया है मिश्रण। एक बार जब द्वारा एक (overrided इसलिए नहीं कि बी में परिभाषा ए.ए. में ओवरराइड प्रतिस्थापित) और बी ने दूसरा, संकलक एक दूसरे के ऊपर चुना नहीं कर सकते क्योंकि इन दोनों के बीच कोई पदानुक्रम (है equaly नाम लेकिन असंबद्ध) तरीकों। यदि आप चाहते हैं, तो इस बारे में सोचें: संकलक एए और बी के निकायों को "मिश्रण" करता है; यदि वह एए से विधि को चुनता है तो यह बी (क्या चाहिए) से विधि को चुनता है, क्योंकि यह ओवरराइड नहीं है, तो आप दो विधियों बी के साथ अटक गए हैं।

इसे हल करने के लिए, आप यह सुनिश्चित करना चाहते हैं कि override एक ही विधि है, जिस स्थिति में संकलक समझ जाएगा कि आप उसी विधि के बारे में बात कर रहे हैं और अंतिम विशेषता मिश्रित को प्राथमिकता देंगे।

अब, बी में विधि ओवरराइड करने के लिए , उस वर्ग भी है एक से प्राप्त करना। तो ऐसा करने के लिए वैधानिक तरीका होगा:

class A { 
    def b { } 
} 

abstract class AA extends A { 
    override def b 
} 

trait B extends A{ 
    def b { println("B") } 
} 

class C extends AA with B {} 

जो ठीक से संकलित करता है।

अब, जब आप कार्य करें:

abstract class AA { 
    def b 
} 

trait B { 
    def b { println("B") } 
} 

class C extends AA with B {} 

यह स्पष्ट है कि दोनों तरीकों में एक ही तो संकलक जानता है वह विशेषता से विधि का उपयोग करने के लिए किया जा सकता है।

अन्य समाधान में शामिल हैं:

  1. बनाओ बी ओवरराइड ए.ए.
  2. एक सार में करें (लेकिन आपको लगता है कि नहीं करना चाहता था)

फिर , समस्या बहुत सूक्ष्म है लेकिन मुझे उम्मीद है कि मैंने इसे थोड़ा स्पष्ट बना दिया है। एक बेहतर समझने के लिए Scala's Stackable Trait Pattern पढ़ें।

+0

धन्यवाद, आपकी व्याख्या बहुत स्पष्ट थी। –

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