क्यों माणिक समर्थन विधि अधिभार नहीं है?


146

रूबी को ओवरलोड करने के लिए सहायक विधि के बजाय मौजूदा तरीकों को अधिलेखित करता है। क्या कोई समझा सकता है कि भाषा को इस तरह क्यों बनाया गया था?

जवाबों:


166

एक ही नाम और अलग-अलग हस्ताक्षर वाले दो तरीकों की घोषणा करके विधि अधिभार प्राप्त किया जा सकता है। ये विभिन्न हस्ताक्षर या तो हो सकते हैं,

  1. विभिन्न डेटा प्रकारों के साथ तर्क, उदाहरण के लिए: method(int a, int b) vs method(String a, String b)
  2. विभिन्न प्रकार के तर्क, उदाहरण के लिए: method(a) vs method(a, b)

रूबी ( डायनामिक टाइप की गई भाषा) में डेटा प्रकार की घोषणा नहीं होने के कारण हम पहले तरीके से ओवरलोडिंग की विधि को प्राप्त नहीं कर सकते हैं ) । तो उपरोक्त विधि को परिभाषित करने का एकमात्र तरीका हैdef(a,b)

दूसरे विकल्प के साथ, ऐसा लग सकता है कि हम विधि अधिभार प्राप्त कर सकते हैं, लेकिन हम नहीं कर सकते। मान लें कि मेरे पास दो तरीके हैं जिनमें विभिन्न तर्क हैं,

def method(a); end;
def method(a, b = true); end; # second argument has a default value

method(10)
# Now the method call can match the first one as well as the second one, 
# so here is the problem.

तो रूबी को एक विधि को बनाए रखने की आवश्यकता है एक अद्वितीय नाम के साथ श्रृंखला देखो।


22
@ Jörg W Mittag का जवाब, नीचे दफन है, निश्चित रूप से पढ़ने लायक है।
user2398029 7

1
और @ डेरेक एकिन्स का जवाब, आगे भी दफन, एक विकल्प प्रदान करता है
सिरिल डचोन-डोरिस

भविष्य rubyists को नोट ... FWIW आप इस अनुबंध मणि के साथ कर सकते egonschiele.github.io/contracts.ruby/#method-overloading
engineerDave

214

"ओवरलोडिंग" एक ऐसा शब्द है जो बस रूबी में भी समझ में नहीं आता है। यह मूल रूप से के लिए "स्थिर तर्क आधारित प्रेषण" एक पर्याय है, लेकिन रूबी नहीं करता है स्थिर प्रेषण सब पर । तो, यही कारण है कि रूबी तर्कों के आधार पर स्थैतिक प्रेषण का समर्थन नहीं करती है, क्योंकि यह स्थैतिक प्रेषण, अवधि का समर्थन नहीं करता है। यह किसी भी प्रकार के स्थैतिक प्रेषण का समर्थन नहीं करता है , चाहे तर्क-आधारित या अन्यथा।

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

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

C # में, आप वास्तव में किसी को भी एनकोड कर सकते हैं 3-SAT समस्या को अधिभार संकल्प हैं, जिसका अर्थ है कि C # में अधिभार संकल्प एनपी-हार्ड है।

अब कोशिश है कि गतिशील के साथ डिस्पैच के , जहां आपके पास अपने सिर में रखने के लिए अतिरिक्त समय आयाम हो।

ऐसी भाषाएं हैं जो गतिशील रूप से एक प्रक्रिया के सभी तर्कों पर आधारित हैं, जैसा कि ऑब्जेक्ट-ओरिएंटेड भाषाओं के विपरीत है, जो केवल "छिपी" शून्य पर भेजती हैं self तर्क । उदाहरण के लिए, कॉमन लिस्प, गतिशील प्रकारों और यहां तक ​​कि सभी तर्कों के गतिशील मूल्यों पर पहुंचता है। क्लोजर सभी तर्कों (जो BTW बेहद शांत और बेहद शक्तिशाली है) के एक मनमाने कार्य पर भेजती है।

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


5
यह सही जवाब है। स्वीकृत उत्तर ओवरसिमलाइज़ होता है। C # DOES ने पैरामीटर और वैकल्पिक मापदंडों को नाम दिया है और अभी भी ओवरलोडिंग को लागू करता है, इसलिए यह उतना आसान नहीं है जितना " def method(a, b = true)काम नहीं करेगा, इसलिए विधि को ओवरलोड करना असंभव है।" यह; यह मुश्किल है। हालांकि मुझे यह उत्तर वास्तव में जानकारीपूर्ण लगा।
tandrewnichols 19

1
@tandrewnichols: बस कुछ विचार देने के लिए कि कैसे "मुश्किल" ओवरलोड रिज़ॉल्यूशन C # में है ... किसी भी 3-SAT समस्या को C # में ओवरलोड रिज़ॉल्यूशन के रूप में एनकोड करना संभव है और कंपाइलर इसे संकलन समय पर हल कर सकता है, इस प्रकार C # NP में ओवरलोड रिज़ॉल्यूशन -हार्ड (3-सैट एनपी-पूर्ण होने के लिए जाना जाता है)। अब ऐसा करने की कल्पना करें कि संकलन के समय एक बार कॉल साइट पर नहीं, बल्कि एक बार हर एक विधि कॉल के लिए रनटाइम पर कॉल करें
जोर्ग डब्ल्यू मित्तग

1
@ JörgWMittag आप अधिभार संकल्प तंत्र में एक 3-SAT समस्या का एन्कोडिंग दिखा लिंक शामिल कर सकते हैं?
स्क्वीडली


2
ऐसा नहीं लगता है कि "ओवरलोडिंग" "स्थिर तर्क-आधारित प्रेषण" का पर्याय है। स्टेटिक तर्क-आधारित प्रेषण केवल ओवरलोडिंग का सबसे आम कार्यान्वयन है। ओवरलोडिंग एक कार्यान्वयन अज्ञेय शब्द है जिसका अर्थ है "एक ही विधि का नाम लेकिन एक ही दायरे में अलग-अलग कार्यान्वयन"।
स्नोविटी

85

मुझे लगता है कि आप ऐसा करने की क्षमता की तलाश कर रहे हैं:

def my_method(arg1)
..
end

def my_method(arg1, arg2)
..
end

रूबी एक अलग तरीके से इसका समर्थन करती है:

def my_method(*args)
  if args.length == 1
    #method 1
  else
    #method 2
  end
end

एक सामान्य पैटर्न भी हैश के रूप में विकल्पों में पारित करने के लिए है:

def my_method(options)
    if options[:arg1] and options[:arg2]
      #method 2
    elsif options[:arg1]
      #method 1
    end
end

my_method arg1: 'hello', arg2: 'world'

उम्मीद है की वो मदद करदे


15
+1 यह प्रदान करने के लिए कि हम में से बहुत से लोग क्या जानना चाहते हैं: रूबी विधियों में परिवर्तनशील तर्कों के साथ कैसे काम करें।
ashes999

3
यह उत्तर वैकल्पिक तर्कों के बारे में अतिरिक्त जानकारी से लाभान्वित हो सकता है। (और शायद तर्कों का नाम भी दिया, अब जब कि वे एक चीज हैं।)
अजेदि ३२

9

मैथड ओवरलोडिंग स्टैटिक टाइपिंग वाली भाषा में समझ में आता है, जहाँ आप विभिन्न प्रकार के तर्कों के बीच अंतर कर सकते हैं

f(1)
f('foo')
f(true)

साथ ही विभिन्न तर्कों के बीच

f(1)
f(1, 'foo')
f(1, 'foo', true)

माणिक में पहला भेद मौजूद नहीं है। रूबी डायनेमिक टाइपिंग या "डक टाइपिंग" का उपयोग करता है। दूसरा अंतर डिफ़ॉल्ट तर्कों द्वारा या तर्कों के साथ काम करने के द्वारा नियंत्रित किया जा सकता है:

def f(n, s = 'foo', flux_compensator = true)
   ...
end


def f(*args)
  case args.size
  when  
     ...
  when 2
    ...
  when 3
    ...
  end
end

इसका मजबूत टाइपिंग से कोई लेना-देना नहीं है। रूबी है दृढ़ता से टाइप किया, सब के बाद।
जोर्ग डब्ल्यू मित्तग

8

यह इस सवाल का जवाब नहीं देता है कि रूबी में ओवरलोडिंग का तरीका क्यों नहीं है, लेकिन तीसरे पक्ष के पुस्तकालय इसे प्रदान कर सकते हैं।

Contracts.ruby पुस्तकालय से अधिक भार अनुमति देता है। उदाहरण ट्यूटोरियल से अनुकूलित:

class Factorial
  include Contracts

  Contract 1 => 1
  def fact(x)
    x
  end

  Contract Num => Num
  def fact(x)
    x * fact(x - 1)
  end
end

# try it out
Factorial.new.fact(5)  # => 120

ध्यान दें कि यह वास्तव में जावा के ओवरलोडिंग से अधिक शक्तिशाली है, क्योंकि आप मूल्यों को मिलान करने के लिए निर्दिष्ट कर सकते हैं (जैसे 1), केवल प्रकार नहीं।

हालांकि आपको इसका उपयोग करते हुए प्रदर्शन में कमी देखने को मिलेगी; आपको यह तय करने के लिए बेंचमार्क चलाना होगा कि आप कितना सहन कर सकते हैं।


1
किसी भी तरह के आईओ के साथ वास्तविक दुनिया के अनुप्रयोगों में, आपके पास केवल 0.1-10% (किस तरह के आईओ पर निर्भर करता है) मंदी होगी।
वाटरलिंक

1

मैं अक्सर निम्नलिखित संरचना करता हूं:

def method(param)
    case param
    when String
         method_for_String(param)
    when Type1
         method_for_Type1(param)

    ...

    else
         #default implementation
    end
end

यह ऑब्जेक्ट के उपयोगकर्ता को स्वच्छ और स्पष्ट method_name: पद्धति का उपयोग करने की अनुमति देता है: लेकिन यदि वह निष्पादन का अनुकूलन करना चाहता है, तो वह सीधे सही विधि को कॉल कर सकता है।

इसके अलावा, यह आपके परीक्षण को स्पष्ट और दांव बनाता है।


1

सवाल के किनारे पर पहले से ही महान जवाब हैं। हालांकि, अगर किसी को अन्य समाधानों की तलाश में कार्यात्मक-रूबी मणि है जो कि अमृत पैटर्न मिलान सुविधाओं से प्रेरित है।

 class Foo
   include Functional::PatternMatching

   ## Constructor Over loading
   defn(:initialize) { @name = 'baz' }
   defn(:initialize, _) {|name| @name = name.to_s }

   ## Method Overloading
   defn(:greet, :male) {
     puts "Hello, sir!"
   }

   defn(:greet, :female) {
     puts "Hello, ma'am!"
   }
 end

 foo = Foo.new or Foo.new('Bar')
 foo.greet(:male)   => "Hello, sir!"
 foo.greet(:female) => "Hello, ma'am!"   
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.