स्काला में स्व-प्रकार और विशेषता विरासत के बीच अंतर क्या है?


9

जब Googled, इस विषय के लिए कई प्रतिक्रियाएँ आती हैं। हालाँकि, मुझे नहीं लगता कि उनमें से कोई भी इन दोनों विशेषताओं के बीच के अंतर को दर्शाने का अच्छा काम करता है। इसलिए मैं एक बार और कोशिश करना चाहूंगा, विशेष रूप से ...

वह कौन सी चीज है जो स्व-प्रकार से की जा सकती है और विरासत से नहीं, और इसके विपरीत?

मेरे लिए, दोनों के बीच कुछ मात्रात्मक, भौतिक अंतर होना चाहिए, अन्यथा वे केवल नाममात्र अलग हैं।

यदि Trait A, B या स्व-प्रकार B का विस्तार करता है, तो क्या वे दोनों यह नहीं बताते कि B का होना एक आवश्यकता है? अंतर कहां है?


मैं उन शर्तों से सावधान हूँ जो आपने इनाम पर निर्धारित की हैं। एक बात के लिए, "भौतिक" अंतर को परिभाषित करें, यह देखते हुए कि यह सभी सॉफ्टवेयर है। इसके अलावा, किसी भी मिश्रित वस्तु के लिए जिसे आप मिक्सिंस के साथ बनाते हैं, आप संभवतः विरासत के साथ फ़ंक्शन में लगभग कुछ बना सकते हैं - यदि आप दृश्य विधियों के संदर्भ में फ़ंक्शन को विशुद्ध रूप से परिभाषित करते हैं। जहाँ वे भिन्नता, लचीलापन और रचनाशीलता में भिन्न होंगे।
इसका 16:25

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

मैं आम तौर पर आप जो कह रहे हैं, उससे अधिक परिचित हूं, लेकिन मैं अभी भी समझ नहीं पा रहा हूं कि इस विशेष मामले में क्या अंतर है। क्या आप कुछ कोड उदाहरण प्रदान कर सकते हैं जो यह दर्शाते हैं कि एक विधि दूसरे की तुलना में अधिक एक्स्टेंसिबल और लचीली है? * एक्सटेंशन के साथ बेस कोड * सेल्फ टाइप्स के साथ बेस कोड * फ़ीचर को एक्सटेंशन स्टाइल में जोड़ा गया * फ़ीचर को सेल्फ टाइप स्टाइल में जोड़ा गया
Mark Canlas

ठीक है, सोचें कि मैं कोशिश कर सकता हूं कि बाउंटी के
दौड़ने

जवाबों:


11

यदि लक्षण A, B को बढ़ाता है, तो A में मिलाने से आप B को जोड़ते हैं या जो बढ़ाते हैं, ठीक बी करते हैं। इसके विपरीत, यदि लक्षण ए में एक आत्म संदर्भ है जो स्पष्ट रूप से बी के रूप में टाइप किया जाता है, तो अंतिम माता-पिता वर्ग को भी बी या वंशज प्रकार के बी में मिश्रण करना चाहिए (और इसे पहले मिलाएं , जो महत्वपूर्ण है)।

यही सबसे महत्वपूर्ण अंतर है। पहले मामले में, सटीक प्रकार B को बिंदु A पर क्रिस्टलीकृत किया जाता है। दूसरे में, मूल वर्ग के डिजाइनर को यह तय करना होता है कि B का कौन सा संस्करण उपयोग किया जाता है, उस बिंदु पर जहां मूल वर्ग की रचना की गई है।

एक और अंतर यह है कि ए और बी एक ही नाम के तरीके प्रदान करते हैं। जहां A, B का विस्तार करता है, A का तरीका B के ओवरराइड करता है। जहाँ A को B के बाद मिलाया जाता है, A की विधि बस जीत जाती है।

टाइप किया गया आत्म संदर्भ आपको बहुत अधिक स्वतंत्रता देता है; A और B के बीच युग्मन ढीला है।

अपडेट करें:

चूंकि आप इन अंतरों के लाभ के बारे में स्पष्ट नहीं हैं ...

यदि आप प्रत्यक्ष उत्तराधिकार का उपयोग करते हैं, तो आप विशेषता A बनाते हैं जो B + A है। तुमने संबंध पत्थर में सेट कर दिया है।

यदि आप टाइप किए गए सेल्फ रेफरेंस का उपयोग करते हैं, तो कोई भी व्यक्ति जो आपकी विशेषता ए का उपयोग कक्षा सी में करना चाहता है, कर सकता है

  • मिक्स B और फिर A को C में मिलाएं।
  • B का एक उपप्रकार और फिर A को C में मिलाएं।
  • मिक्स A को C में, जहाँ C, B का उपवर्ग है।

और यह उनके विकल्पों की सीमा नहीं है, जिस तरह से स्काला आपको एक कोड ब्लॉक के साथ सीधे उसके निर्माणकर्ता के रूप में एक विशेषता को तुरंत हटाने की अनुमति देता है।

ए की पद्धति जीतने के बीच के अंतर के लिए , क्योंकि ए को अंतिम में मिलाया जाता है, ए की तुलना में एक विस्तारित बी, इस पर विचार करें ...

जहाँ आप लक्षणों के अनुक्रम में मिलाते हैं, जब भी विधि foo()को लागू किया जाता है, तो कंपाइलर अंतिम विशेषता को देखने के लिए मिश्रित हो जाता है foo(), तब (यदि नहीं मिला), तो यह अनुक्रम को बाईं ओर तब तक ट्रेस करता है जब तक कि वह एक गुण नहीं खोज लेता है जो लागू होता है foo()और उपयोग करता है उस। ए में कॉल करने का विकल्प भी होता है super.foo(), जो अनुक्रम को बाईं ओर तब तक ट्रेस करता है जब तक कि यह एक कार्यान्वयन नहीं पाता है, और इसी तरह।

अतः यदि A का B के लिए टाइप किया गया आत्म संदर्भ है और A का लेखक जानता है कि B लागू करता है foo(), तो A यह super.foo()जानकर कॉल कर सकता है कि यदि और कुछ नहीं प्रदान करता है foo(), तो बी विल। हालांकि, क्लास सी के निर्माता के पास किसी भी अन्य गुण को लागू करने का विकल्प होता है foo(), जिसमें ए और उसके बदले ए मिलेगा।

फिर, यह एक विस्तारित बी की तुलना में बहुत अधिक शक्तिशाली और कम सीमित है और सीधे बी के संस्करण को बुला रहा है foo()


A जीत बनाम A ओवरराइडिंग के बीच कार्यात्मक अंतर क्या है? मैं विभिन्न मामलों के माध्यम से दोनों मामलों में ए मिल रहा हूं? और आपके पहले उदाहरण में ... आपके पहले पैराग्राफ में, ए का विस्तार सुपरऑफबी क्यों नहीं है? यह सिर्फ ऐसा लगता है कि हम या तो तंत्र का उपयोग कर समस्या को फिर से तैयार कर सकते हैं। मुझे लगता है कि मैं एक उपयोग के मामले को नहीं देख रहा हूं जहां यह संभव नहीं है। या मैं बहुत सी चीजों को मान रहा हूं।
मार्क कैनलास

उम, आप बी का एक उपवर्ग का विस्तार क्यों करना चाहते हैं , यदि बी परिभाषित करता है कि आपको क्या चाहिए? आत्म संदर्भ बी (या एक उपवर्ग) को उपस्थित होने के लिए मजबूर करता है, लेकिन tbe डेवलपर को विकल्प देता है? वे आपके द्वारा लिखी गई विशेषता ए के बाद लिखी गई चीज़ों में मिश्रण कर सकते हैं, जब तक कि वह बी का विस्तार करता है। आप उन्हें क्यों विवश करते हैं, जब आपने लक्षण ए लिखा था तब क्या उपलब्ध था?
इसका क्रेज

अंतर को स्पष्ट करने के लिए अद्यतन किया गया।
इसका कर्क

@itsbruce क्या कोई वैचारिक अंतर है? आईएस-ए बनाम एचएएस-ए है?
जस

@ जस लक्षण और बी के बीच संबंधों के संदर्भ में , विरासत IS-A है जबकि टाइप किया गया आत्म-संदर्भ एचएएस-ए (एक संरचनात्मक संबंध) देता है। जिस वर्ग में गुण मिलाया जाता है, उसका परिणाम IS-A होता है , फिर भी।
इसका कर्क

0

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

trait A1 {
  self: B =>

  def doit {
    println(bar)
  }
}

trait A2 extends B {
  def doit {
    println(bar)
  }
}

trait B {
  def bar = "default bar"
}

trait BX extends B {
  override def bar = "bar bx"
}

trait BY extends B {
  override def bar = "bar by"
}

object Test extends App {
  // object Thing1 extends A1  // FAIL: does not conform to A1 self-type
  object Thing1 extends A1 with B
  object Thing2 extends A2

  object Thing1X extends A1 with BX
  object Thing1Y extends A1 with BY
  object Thing2X extends A2 with BX
  object Thing2Y extends A2 with BY

  Thing1.doit  // default bar
  Thing2.doit  // default bar
  Thing1X.doit // bar bx
  Thing1Y.doit // bar by
  Thing2X.doit // bar bx
  Thing2Y.doit // bar by

  // up-cast
  val a1: A1 = Thing1Y
  val a2: A2 = Thing2Y

  // println(a1.bar)    // FAIL: not visible
  println(a2.bar)       // bar bx
  // println(a2.bary)   // FAIL: not visible
  println(Thing2Y.bary) // 42
}

एक महत्वपूर्ण अंतर यह है कि IMO A1यह उजागर नहीं करता है कि इसे Bकुछ भी करने की आवश्यकता है जो इसे केवल देखता है A1(जैसे कि अप-कास्ट पार्ट्स में सचित्र)। एकमात्र कोड जो वास्तव में यह देखेगा कि एक विशेष विशेषज्ञता का Bउपयोग किया जाता है, वह कोड है जो स्पष्ट रूप से रचित प्रकार (जैसे Think*{X,Y}) के बारे में जानता है ।

एक और बिंदु यह है कि A2(विस्तार के साथ) वास्तव में उपयोग करेगा Bयदि कुछ और निर्दिष्ट नहीं किया गया है जबकि A1(स्व-प्रकार) यह नहीं कहता है कि Bजब तक ओवरराइड नहीं किया जाएगा, तब तक कंक्रीट बी को स्पष्ट रूप से उपयोग किया जाना चाहिए जब ऑब्जेक्ट्स को तत्काल किया जाता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.