रिटर्न प्रकार द्वारा ओवरलोडिंग?


252

अधिक मुख्यधारा की वैधानिक रूप से टाइप की गई भाषाएं फ़ंक्शन / विधि को रिटर्न प्रकार द्वारा ओवरलोडिंग का समर्थन क्यों नहीं करती हैं? मैं ऐसा करने के बारे में सोच भी नहीं सकता। यह पैरामीटर प्रकार द्वारा अधिभार का समर्थन करने से कम उपयोगी या उचित नहीं लगता है। यह इतना कम लोकप्रिय कैसे हुआ?


जवाबों:


523

दूसरों क्या कह रहे हैं, वापसी प्रकार से अधिक भार के विपरीत है संभव और है कुछ आधुनिक भाषाओं के द्वारा किया। सामान्य आपत्ति यह है कि जैसे कोड में है

int func();
string func();
int main() { func(); }

आप यह नहीं बता सकते कि किसे func()बुलाया जा रहा है। इसे कुछ तरीकों से हल किया जा सकता है:

  1. इस तरह की स्थिति में किस फ़ंक्शन को कहा जाता है, यह निर्धारित करने के लिए एक पूर्वानुमान विधि है।
  2. जब भी ऐसी स्थिति होती है, यह एक संकलन-समय की त्रुटि है। हालाँकि, एक वाक्यविन्यास है जो प्रोग्रामर को अनुमति नहीं देता है, जैसे int main() { (string)func(); }
  3. साइड इफेक्ट नहीं है। यदि आपके साइड इफेक्ट्स नहीं हैं और आप कभी किसी फ़ंक्शन के रिटर्न मान का उपयोग नहीं करते हैं, तो कंपाइलर पहले स्थान पर फ़ंक्शन को कॉल करने से कभी भी बच सकता है।

मैं नियमित रूप से ( ab ) भाषाओं में से दो वापसी प्रकार द्वारा अधिभार का उपयोग करता हूं : पर्ल और हास्केल । मुझे बताएं कि वे क्या करते हैं।

में पर्ल , वहाँ में एक बुनियादी अंतर है अदिश और सूची संदर्भ (और अन्य, लेकिन हम नाटक करता हूँ वहाँ दो हैं)। पर्ल में प्रत्येक अंतर्निहित फ़ंक्शन उस संदर्भ के आधार पर अलग-अलग चीजें कर सकता है जिसमें इसे कहा जाता है। उदाहरण के लिए, joinऑपरेटर बलों के संदर्भ को सूचीबद्ध करता है (शामिल होने पर), जबकि scalarऑपरेटर स्केलर के संदर्भ को बल देता है, इसलिए तुलना करें:

print join " ", localtime(); # printed "58 11 2 14 0 109 3 13 0" for me right now
print scalar localtime(); # printed "Wed Jan 14 02:12:44 2009" for me right now.

पर्ल में प्रत्येक ऑपरेटर स्केलर संदर्भ में कुछ और सूची के संदर्भ में कुछ करता है, और वे अलग-अलग हो सकते हैं, जैसा कि सचित्र है। (यह सिर्फ यादृच्छिक परिचालकों के लिए नहीं है localtime। यदि आप @aसूची के संदर्भ में किसी सरणी का उपयोग करते हैं , तो यह सरणी को लौटाता है, जबकि स्केलर संदर्भ में, यह तत्वों की संख्या लौटाता है। इसलिए उदाहरण के print @aलिए तत्वों को print 0+@aप्रिंट करता है , जबकि आकार को प्रिंट करता है। ) इसके अलावा, प्रत्येक ऑपरेटर एक संदर्भ को बाध्य कर सकता है, उदाहरण के लिए +स्केलर संदर्भ को मजबूर करता है। man perlfuncदस्तावेजों में हर प्रविष्टि । उदाहरण के लिए, यहां प्रविष्टि का हिस्सा है glob EXPR:

सूची के संदर्भ में, EXPRमानक यूनिक्स शेल के रूप में इस तरह के मूल्य पर फ़ाइल नाम विस्तार की एक (संभवतः खाली) सूची देता /bin/cshहै। स्केलर के संदर्भ में, ग्लोब इस तरह के फ़ाइलनाम विस्तार के माध्यम से पुनरावृत्त करता है, जब सूची समाप्त हो जाती है तो अपराजित हो जाती है।

अब, सूची और अदिश संदर्भ के बीच क्या संबंध है? खैर, man perlfuncकहते हैं

निम्नलिखित महत्वपूर्ण नियम को याद रखें: ऐसा कोई नियम नहीं है जो सूची के संदर्भ में एक अभिव्यक्ति के व्यवहार को स्केलर के संदर्भ में, या उसके विपरीत व्यवहार से संबंधित करता है। यह दो पूरी तरह से अलग चीजें कर सकता है। प्रत्येक ऑपरेटर और फ़ंक्शन यह तय करता है कि स्केलर के संदर्भ में किस प्रकार का मान लौटना उचित होगा। कुछ ऑपरेटर सूची की लंबाई लौटाते हैं जो सूची के संदर्भ में वापस कर दी गई होती। कुछ ऑपरेटर सूची में पहला मान लौटाते हैं। कुछ ऑपरेटर सूची में अंतिम मान लौटाते हैं। कुछ ऑपरेटर सफल संचालन की एक गिनती लौटाते हैं। सामान्य तौर पर, वे वही करते हैं जो आप चाहते हैं, जब तक आप निरंतरता नहीं चाहते।

इसलिए यह एकल कार्य होने का एक साधारण मामला नहीं है, और फिर आप अंत में सरल रूपांतरण करते हैं। वास्तव में, मैंने localtimeउस कारण के लिए उदाहरण चुना ।

यह केवल बिल्ट-इन नहीं है जिसमें यह व्यवहार है। कोई भी उपयोगकर्ता ऐसे फ़ंक्शन का उपयोग करके परिभाषित कर सकता है wantarray, जो आपको सूची, स्केलर और शून्य संदर्भ के बीच अंतर करने की अनुमति देता है। इसलिए, उदाहरण के लिए, यदि आप शून्य संदर्भ में कहे जा रहे हैं, तो आप कुछ नहीं करने का निर्णय ले सकते हैं।

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

sub func {
    if( not defined wantarray ) {
        print "void\n";
    } elsif( wantarray ) {
        print "list\n";
    } else {
        print "scalar\n";
    }
}

func(); # prints "void"
() = func(); # prints "list"
0+func(); # prints "scalar"

(नोट: मैं कभी-कभी पर्ल ऑपरेटर से कह सकता हूं जब मेरा मतलब है कि यह इस चर्चा के लिए महत्वपूर्ण नहीं है।)

हास्केल दूसरे दृष्टिकोण को अपनाता है, जिसका दुष्प्रभाव नहीं है। इसमें एक मजबूत प्रकार की प्रणाली भी है, और इसलिए आप निम्नलिखित की तरह कोड लिख सकते हैं:

main = do n <- readLn
          print (sqrt n) -- note that this is aligned below the n, if you care to run this

यह कोड मानक इनपुट से एक फ्लोटिंग पॉइंट नंबर पढ़ता है, और इसके वर्गमूल को प्रिंट करता है। लेकिन इसमें आश्चर्य की बात क्या है? खैर, प्रकार readLnहै readLn :: Read a => IO a। इसका मतलब यह है कि किसी भी प्रकार के लिए Read(औपचारिक रूप से, प्रत्येक प्रकार जो कि Readटाइप वर्ग का एक उदाहरण है ), readLnइसे पढ़ सकते हैं। हास्केल को कैसे पता चला कि मैं एक फ्लोटिंग पॉइंट नंबर पढ़ना चाहता था? खैर, का प्रकार sqrtहै sqrt :: Floating a => a -> a, जो अनिवार्य रूप से मतलब है कि sqrtकेवल अस्थायी बिंदु संख्या को इनपुट के रूप में स्वीकार कर सकता है, और इसलिए हास्केल ने अनुमान लगाया कि मैं क्या चाहता था।

क्या होता है जब हास्केल जो चाहते हैं वह अनुमान नहीं लगा सकता है? खैर, कुछ संभावनाएं हैं। अगर मैं रिटर्न वैल्यू का उपयोग बिल्कुल नहीं करता हूं, तो हास्केल सीधे फ़ंक्शन को पहले स्थान पर नहीं बुलाएगा। हालांकि, अगर मैं कर दिया गया मान का उपयोग करें, तो हास्केल शिकायत है कि यह प्रकार अनुमान नहीं लगा सकता:

main = do n <- readLn
          print n
-- this program results in a compile-time error "Unresolved top-level overloading"

मैं अपने इच्छित प्रकार को निर्दिष्ट करके अस्पष्टता को हल कर सकता हूं:

main = do n <- readLn
          print (n::Int)
-- this compiles (and does what I want)

वैसे भी, इस पूरी चर्चा का मतलब यह है कि रिटर्न वैल्यू द्वारा ओवरलोडिंग संभव है और किया जाता है, जो आपके प्रश्न का हिस्सा है।

आपके प्रश्न का दूसरा भाग यही है कि अधिक भाषाएँ ऐसा क्यों नहीं करती हैं। मैं दूसरों को इसका जवाब दूंगा। हालांकि, कुछ टिप्पणियां: सिद्धांत कारण संभवतः यह है कि तर्क के प्रकार से ओवरलोडिंग की तुलना में भ्रम का अवसर वास्तव में यहां अधिक है। आप अलग-अलग भाषाओं से युक्तियों को भी देख सकते हैं:

Ada : "ऐसा प्रतीत हो सकता है कि सरलतम अधिभार संकल्प नियम सब कुछ का उपयोग करना है - सभी जानकारी यथासंभव विस्तृत संदर्भ से - अतिभारित संदर्भ को हल करने के लिए। यह नियम सरल हो सकता है, लेकिन यह उपयोगी नहीं है। इसके लिए मानव पाठक की आवश्यकता है। मनमाने ढंग से पाठ के बड़े टुकड़ों को स्कैन करने के लिए, और मनमाने ढंग से जटिल inferences (जैसे कि (g) ऊपर) को बनाने के लिए। हमारा मानना ​​है कि एक बेहतर नियम वह है जो स्पष्ट रूप से कार्य करता है एक मानव पाठक या एक कंपाइलर को प्रदर्शन करना चाहिए, और इससे यह कार्य हो जाता है मानव पाठक के लिए जितना संभव हो उतना स्वाभाविक है। ”

C ++ (उपधारा 7.4.1of बज़्ने स्ट्रॉस्ट्रुप की "द C ++ प्रोग्रामिंग लैंग्वेज"): "रिटर्न प्रकार को ओवरलोड रिज़ॉल्यूशन में नहीं माना जाता है। इसका कारण व्यक्तिगत ऑपरेटर या फ़ंक्शन कॉल संदर्भ-स्वतंत्र के लिए रिज़ॉल्यूशन रखने पर विचार करें।"

float sqrt(float);
double sqrt(double);

void f(double da, float fla)
{
    float fl = sqrt(da);     // call sqrt(double)
    double d = sqrt(da); // call sqrt(double)
    fl = sqrt(fla);            // call sqrt(float)
    d = sqrt(fla);             // call sqrt(float)
}

यदि रिटर्न प्रकार को ध्यान में रखा जाता है, तो sqrt()अलगाव में कॉल को देखना और निर्धारित करना संभव नहीं होगा कि कौन सा फ़ंक्शन कहा जाता है। "(तुलना के लिए ध्यान दें, कि हास्केल में कोई अंतर्निहित रूपांतरण नहीं हैं ।)

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

पुनश्च। अंतिम नोट के रूप में, यह एक चाल के साथ सी ++ में रिटर्न वैल्यू द्वारा अधिभार करना संभव है। गवाह:

struct func {
    operator string() { return "1";}
    operator int() { return 2; }
};

int main( ) {
    int x    = func(); // calls int version
    string y = func(); // calls string version
    double d = func(); // calls int version
    cout << func() << endl; // calls int version
    func(); // calls neither
}

महान पोस्ट, लेकिन आप स्पष्ट करना चाहते हैं कि पढ़ना क्या है (स्ट्रिंग -> कुछ)।
थॉमस एडिंग

C ++ यह भी बताता है कि आपने const / not const द्वारा ओवरलोड का मान लिया है। stackoverflow.com/questions/251159/…
जियोन

3
ज़बरदस्ती ऑपरेटर्स को ओवरलोड करने के साथ आपकी आखिरी चाल के लिए, "कॉट" लाइन कभी-कभी काम करती है, लेकिन कोड में किए गए लगभग किसी भी बदलाव से यह "ऑपरेटर <<" के लिए "अस्पष्ट ओवरलोड" देता है।
स्टीव

1
मैं जिस दृष्टिकोण का पक्ष लूंगा, उसे आवश्यकता होगी कि एक अधिभार को "पसंदीदा" के रूप में चिह्नित किया जाए; कंपाइलर केवल पसंदीदा अधिभार का उपयोग करके बाइंडिंग से शुरू होगा, और फिर यह निर्धारित करेगा कि कोई गैर-अधिभार अधिभार एक सुधार होगा या नहीं। अन्य बातों के अलावा, मान लें कि Fooऔर Barद्विदिश रूपांतरण का समर्थन करते हैं, और एक विधि Fooआंतरिक रूप से लेकिन रिटर्न प्रकार का उपयोग करती है Bar। यदि इस तरह की विधि को कोड द्वारा कहा जाता है जो तुरंत परिणाम टाइप करने के लिए मजबूर करेगा Foo, तो Barरिटर्न प्रकार का उपयोग करके काम किया जा सकता है, लेकिन Fooएक बेहतर होगा। BTW, मैं एक साधन भी देखना चाहूंगा जिसके द्वारा ...
सुपरकैट

... एक विधि यह बता सकती है कि निर्माण में किस प्रकार का उपयोग किया जाना चाहिए var someVar = someMethod();( जैसे कि यह निर्दिष्ट करें कि इसकी वापसी का उपयोग इस तरह से नहीं किया जाना चाहिए)। उदाहरण के लिए, एक धाराप्रवाह इंटरफ़ेस को लागू करने वाले प्रकारों का एक परिवार, जो परिवर्तनशील और अपरिवर्तनीय संस्करणों से लाभान्वित हो सकता है, इसलिए एक उत्परिवर्तित वस्तु, म्यूट एक्स की प्रतिलिपि var thing2 = thing1.WithX(3).WithY(5).WithZ(9);होगा , और उस परिवर्तनशील वस्तु को वापस कर देगा; Y को म्यूट करेगा और उसी ऑब्जेक्ट को लौटाएगा; इसी तरह `WithZ (9)। फिर असाइनमेंट एक अपरिवर्तनीय प्रकार में बदल जाएगा। WithX(3)thing1WithY(5)
सुपरकैट

37

यदि फ़ंक्शंस रिटर्न प्रकार द्वारा ओवरलोड किए गए थे और आपके पास ये दो ओवरलोड थे

int func();
string func();

ऐसा कोई तरीका नहीं है कि संकलक यह पता लगा सके कि उन दोनों कार्यों में से कौन सा कॉल इस तरह से देखने पर कॉल करेगा

void main() 
{
    func();
}

इस कारण से, भाषा डिजाइनर अक्सर रिटर्न-वैल्यू ओवरलोडिंग को अस्वीकार कर देते हैं।

कुछ भाषाओं (जैसे MSIL के रूप में), तथापि, है वापसी प्रकार से अधिक भार अनुमति देते हैं। वे भी निश्चित रूप से उपरोक्त कठिनाई का सामना करते हैं, लेकिन उनके पास वर्कअराउंड है, जिसके लिए आपको उनके प्रलेखन से परामर्श करना होगा।


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

2
@ Jörg W Mittag: आप यह नहीं देखते कि क्या कार्य करते हैं। वे आसानी से अलग दुष्प्रभाव हो सकते हैं ।
ए रेक्स

2
@ Jörg - अधिकांश मुख्यधारा की प्रोग्रामिंग भाषाओं (C / C ++, C #, Java, आदि) में आमतौर पर साइड-इफेक्ट्स होते हैं। वास्तव में, मुझे लगता है कि साइड इफेक्ट्स के साथ कार्य कम से कम उन लोगों के रूप में आम हैं।
माइकल बूर

6
यहां देर से कूदते हुए, लेकिन कुछ संदर्भों में "फ़ंक्शन" की संकीर्ण परिभाषा है (अनिवार्य रूप से) "एक विधि जिसका कोई दुष्प्रभाव नहीं है"। अधिक बोलचाल की भाषा में, "फ़ंक्शन" का उपयोग अक्सर "विधि" या "सबरूटीन" के साथ किया जाता है। Jorg या तो कठोर या पांडित्यपूर्ण हो रहा है, आपकी बात पर निर्भर करता है :)
AwesomeTown

3
बाद में भी कूदते हुए, देखने के कुछ बिंदु कठोर या पांडित्य के अलावा अन्य विशेषणों का उपयोग कर सकते हैं
पैट्रिक मैकडॉनल्ड

27

ऐसी भाषा में, आप निम्नलिखित को कैसे हल करेंगे:

f(g(x))

अगर fभार के लिए किया था void f(int)और void f(string)और gभार के लिए किया था int g(int)और string g(int)? आपको किसी तरह के डिसएम्बिगेटर की आवश्यकता होगी।

मुझे लगता है कि जिन स्थितियों में आपको इसकी आवश्यकता हो सकती है, वे फ़ंक्शन के लिए एक नया नाम चुनकर बेहतर सेवा करेंगे।


2
नियमित रूप से ओवरलोडिंग के परिणामस्वरूप अस्पष्टता भी हो सकती है। मुझे लगता है कि ये आम तौर पर आवश्यक जातियों की संख्या की गणना करके हल किए जाते हैं, लेकिन यह हमेशा काम नहीं करता है।
जे कॉनरोड

1
हां, मानक रूपांतरणों को सटीक मिलान, प्रचार और रूपांतरण में स्थान दिया गया है: void f (int); शून्य च (लंबा); f ( 'एक'); कॉल एफ (इंट), क्योंकि यह केवल एक पदोन्नति है, जबकि लंबे समय तक परिवर्तित करना रूपांतरण है। शून्य च (फ्लोट); शून्य च (छोटा); च (10); दोनों के लिए रूपांतरण की आवश्यकता होगी: कॉल अस्पष्ट है।
जोहान्स स्काउब -

यदि भाषा में आलसी मूल्यांकन है, तो यह उतनी समस्या नहीं है।
५:०१

अपवोट, पैरामीटर प्रकार ओवरलोडिंग और रिटर्न प्रकार ओवरलोडिंग की बातचीत को रेक्स के पोस्ट में संबोधित नहीं किया गया है। बहुत अच्छी बात है।
जोसफ गार्विन

1
क्या मैं एक भाषा डिजाइन कर रहा था, मेरा नियम यह होगा कि किसी भी अतिभारित फ़ंक्शन के लिए, प्रत्येक पैरामीटर हस्ताक्षर में एक वापसी-प्रकार डिफ़ॉल्ट के रूप में निर्दिष्ट होना चाहिए; प्रत्येक फ़ंक्शन कॉल डिफ़ॉल्ट प्रकार का उपयोग करेगा मानकर एक कंपाइलर शुरू होगा। एक बार ऐसा किया गया था, हालांकि, हर स्थिति में जहां किसी फ़ंक्शन का रिटर्न मान तुरंत डाला गया था या किसी और चीज के लिए ज़ब्त किया गया था, कंपाइलर एक अधिभार के लिए जांच करेगा जिसका पैरामीटर हस्ताक्षर समान है, लेकिन जिसका वापसी प्रकार एक बेहतर मैच है (या संभवतः शून्य) । मैं शायद ऐसे ओवरलोड के लिए "ओवरराइड-वन - ओवरराइड-ऑल" नियम भी लागू करूंगा।
सुपरकैट

19

एक और इसी तरह के प्रश्न (डुबकी?) से C ++ विशिष्ट उत्तर चोरी करने के लिए :


फ़ंक्शन रिटर्न प्रकार केवल ओवरलोड रिज़ॉल्यूशन में खेलने के लिए नहीं आते हैं क्योंकि स्ट्रॉस्ट्रुप (मैं अन्य C ++ आर्किटेक्ट्स से इनपुट के साथ मानता हूं) ओवरलोड रिज़ॉल्यूशन 'संदर्भ स्वतंत्र' होना चाहता था। 7.4.1 - "C ++ प्रोग्रामिंग लैंग्वेज, थर्ड एडिशन" से "ओवरलोडिंग और रिटर्न टाइप" देखें।

इसका कारण व्यक्तिगत ऑपरेटर या फ़ंक्शन कॉल संदर्भ-स्वतंत्र के लिए रिज़ॉल्यूशन रखना है।

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

और, भगवान जानता है, सी ++ अधिभार संकल्प काफी जटिल है क्योंकि यह खड़ा है ...


5

हैस्केल में यह संभव है, भले ही इसमें फ़ंक्शन ओवरलोडिंग न हो। हास्केल प्रकार की कक्षाओं का उपयोग करता है। एक कार्यक्रम में आप देख सकते हैं:

class Example a where
    example :: Integer -> a

instance Example Integer where  -- example is now implemented for Integer
    example :: Integer -> Integer
    example i = i * 10

फंक्शन ओवरलोडिंग खुद इतना लोकप्रिय नहीं है। ज्यादातर भाषाओं को मैंने इसके साथ देखा है C ++, शायद जावा और / या C #। सभी गतिशील भाषाओं में इसके लिए एक आशुलिपि है:

define example:i
  ↑i type route:
    Integer = [↑i & 0xff]
    String = [↑i upper]


def example(i):
    if isinstance(i, int):
        return i & 0xff
    elif isinstance(i, str):
        return i.upper()

इसलिए इसमें ज्यादा दम नहीं है। अधिकांश लोगों को इस बात में कोई दिलचस्पी नहीं है कि क्या भाषा आपको एक लाइन छोड़ने में मदद कर सकती है जहां आप कभी भी इसका उपयोग करते हैं।

पैटर्न मिलान कुछ हद तक ओवरलोडिंग के समान है, और मुझे लगता है कि कभी-कभी समान रूप से काम करते हैं। यह आम नहीं है, क्योंकि यह केवल कुछ कार्यक्रमों के लिए उपयोगी है और अधिकांश भाषाओं पर लागू करने के लिए मुश्किल है।

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

  • गतिशील टाइपिंग
  • सूचियों, शब्दकोशों और यूनिकोड स्ट्रिंग्स के लिए आंतरिक समर्थन
  • अनुकूलन (JIT, टाइपिंग, संकलन)
  • एकीकृत तैनाती उपकरण
  • पुस्तकालय का समर्थन
  • सामुदायिक समर्थन और सभा स्थल
  • समृद्ध मानक पुस्तकालय
  • अच्छा वाक्यविन्यास
  • Eval प्रिंट लूप पढ़ें
  • चिंतनशील प्रोग्रामिंग के लिए समर्थन

3
हास्केल में ओवरलोडिंग है। टाइप कक्षाएं भाषा की सुविधा है जिसका उपयोग ओवरलोड कार्यों को परिभाषित करने के लिए किया जाता है।
Lii

2

अच्छा जवाब! विशेष रूप से A.Rex का उत्तर बहुत विस्तृत और शिक्षाप्रद है। जैसा कि वह बताते हैं, C ++ उपयोगकर्ता-आपूर्ति के प्रकार-रूपांतरण ऑपरेटरों पर विचार करता है जब संकलित किया जाता है lhs = func(); (जहां फंक वास्तव में एक संरचना का नाम है) । मेरा वर्कअराउंड थोड़ा अलग है - बेहतर नहीं है, बस अलग है (हालांकि यह एक ही मूल विचार पर आधारित है)।

जबकि मैं लिखना चाहता था ...

template <typename T> inline T func() { abort(); return T(); }

template <> inline int func()
{ <<special code for int>> }

template <> inline double func()
{ <<special code for double>> }

.. etc, then ..

int x = func(); // ambiguous!
int x = func<int>(); // *also* ambiguous!?  you're just being difficult, g++!

मैं एक ऐसे समाधान के साथ समाप्त हुआ जो एक मानकीकृत संरचना (टी = रिटर्न प्रकार के साथ) का उपयोग करता है:

template <typename T>
struct func
{
    operator T()
    { abort(); return T(); } 
};

// explicit specializations for supported types
// (any code that includes this header can add more!)

template <> inline
func<int>::operator int()
{ <<special code for int>> }

template <> inline
func<double>::operator double()
{ <<special code for double>> }

.. etc, then ..

int x = func<int>(); // this is OK!
double d = func<double>(); // also OK :)

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

template <typename T>
struct func<T*>
{
    operator T*()
    { <<special handling for T*>> } 
};

एक नकारात्मक के रूप में, आप int x = func();मेरे समाधान के साथ नहीं लिख सकते । आपको लिखना होगा int x = func<int>();। आपको स्पष्ट रूप से कहना होगा कि रिटर्न टाइप क्या है, बजाय संकलक को टाइप रूपांतरण ऑपरेटरों को देखकर इसे बाहर निकालने के लिए कहना। मैं कहूंगा कि "मेरे" समाधान और ए। रेक्स दोनों ही इस सी ++ दुविधा से निपटने के तरीकों के एक परेतो-इष्टतम सामने हैं


1

यदि आप विभिन्न रिटर्न प्रकारों के साथ तरीकों को ओवरलोड करना चाहते हैं, तो बस अधिभार निष्पादन की अनुमति देने के लिए डिफ़ॉल्ट मान के साथ एक डमी पैरामीटर जोड़ें , लेकिन पैरामीटर प्रकार को अलग नहीं होना चाहिए, इसलिए ओवरलोड तर्क अगले काम करता है जैसे कि डेल्फी पर:

type    
    myclass = class
    public
      function Funct1(dummy: string = EmptyStr): String; overload;
      function Funct1(dummy: Integer = -1): Integer; overload;
    end;

इसे इस तरह से उपयोग करें

procedure tester;
var yourobject : myclass;
  iValue: integer;
  sValue: string;
begin
  yourobject:= myclass.create;
  iValue:= yourobject.Funct1(); //this will call the func with integer result
  sValue:= yourobject.Funct1(); //this will call the func with string result
end;

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

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

निश्चित रूप से ऐसे परिदृश्य हैं जहां डमी पैरामीटर उपयोगी होते हैं, जैसे मानचित्र या गुना संचालन में लैम्ब्डा या इंटरफ़ेस लागू करते समय। लेकिन एक अतिभार पैदा करने के लिए, नहीं, मैं असहमत होने के लिए भीख माँगता हूँ। कोई ज़रूरत नहीं है और यह शोर है कि प्रोग्रामर बिना रह सकते हैं।
हाबिल

0

जैसा कि पहले ही दिखाया गया है - एक फ़ंक्शन की अस्पष्ट कॉल जो केवल रिटर्न प्रकार से भिन्न होती है, अस्पष्टता का परिचय देती है। अस्पष्टता दोषपूर्ण कोड को प्रेरित करती है। दोषपूर्ण कोड से बचा जाना चाहिए।

अस्पष्टता के प्रयास से प्रेरित जटिलता से पता चलता है कि यह एक अच्छा हैक नहीं है। एक बौद्धिक अभ्यास के अलावा - संदर्भ मापदंडों के साथ प्रक्रियाओं का उपयोग क्यों नहीं करें।

procedure(reference string){};
procedure(reference int){};
string blah;
procedure(blah)

क्योंकि आप आसानी से "वापसी" मूल्यों का तुरंत उपयोग नहीं कर सकते। आपको प्रत्येक कॉल एक लाइन पर करना होगा, जैसा कि विरोध किया गया हैdoing(thisVery(deeplyNested(), andOften(butNotAlways()), notReally()), goodCode());
Adowrath

0

यदि आप इसे थोड़ा अलग तरीके से देखते हैं, तो यह ओवरलोडिंग सुविधा को प्रबंधित करना मुश्किल नहीं है। निम्नलिखित को धयान मे रखते हुए,

public Integer | String f(int choice){
if(choice==1){
return new string();
}else{
return new Integer();
}}

यदि कोई भाषा ओवरलोडिंग करती है तो यह पैरामीटर को ओवरलोडिंग की अनुमति देगा, लेकिन दोहराव नहीं। इससे समस्या का समाधान होगा:

main (){
f(x)
}

क्योंकि चुनने के लिए केवल एक f (int पसंद) है।


0

.NET में, कभी-कभी हम जेनेरिक परिणाम से वांछित आउटपुट को इंगित करने के लिए एक पैरामीटर का उपयोग करते हैं, और फिर जो हम उम्मीद करते हैं उसे पाने के लिए रूपांतरण किया।

सी#

public enum FooReturnType{
        IntType,
        StringType,
        WeaType
    }

    class Wea { 
        public override string ToString()
        {
            return "Wea class";
        }
    }

    public static object Foo(FooReturnType type){
        object result = null;
        if (type == FooReturnType.IntType) 
        {
            /*Int related actions*/
            result = 1;
        }
        else if (type == FooReturnType.StringType)
        {
            /*String related actions*/
            result = "Some important text";
        }
        else if (type == FooReturnType.WeaType)
        {
            /*Wea related actions*/
            result = new Wea();
        }
        return result;
    }

    static void Main(string[] args)
    {
        Console.WriteLine("Expecting Int from Foo: " + Foo(FooReturnType.IntType));
        Console.WriteLine("Expecting String from Foo: " + Foo(FooReturnType.StringType));
        Console.WriteLine("Expecting Wea from Foo: " + Foo(FooReturnType.WeaType));
        Console.Read();
    }

शायद यह उदाहरण भी मदद कर सकता है:

सी ++

    #include <iostream>

enum class FooReturnType{ //Only C++11
    IntType,
    StringType,
    WeaType
}_FooReturnType;

class Wea{
public:
    const char* ToString(){
        return "Wea class";
    }
};

void* Foo(FooReturnType type){
    void* result = 0;
    if (type == FooReturnType::IntType) //Only C++11
    {
        /*Int related actions*/
        result = (void*)1;
    }
    else if (type == FooReturnType::StringType) //Only C++11
    {
        /*String related actions*/
        result = (void*)"Some important text";
    }
    else if (type == FooReturnType::WeaType) //Only C++11
    {
        /*Wea related actions*/
        result = (void*)new Wea();
    }
    return result;
}

int main(int argc, char* argv[])
{
    int intReturn = (int)Foo(FooReturnType::IntType);
    const char* stringReturn = (const char*)Foo(FooReturnType::StringType);
    Wea *someWea = static_cast<Wea*>(Foo(FooReturnType::WeaType));
    std::cout << "Expecting Int from Foo: " << intReturn << std::endl;
    std::cout << "Expecting String from Foo: " << stringReturn << std::endl;
    std::cout << "Expecting Wea from Foo: " << someWea->ToString() << std::endl;
    delete someWea; // Don't leak oil!
    return 0;
}

1
यह एक प्रकार का हैकिश है, और यदि उपयोगकर्ता ठीक से परिणाम नहीं देता है, या यदि डेवलपर एनम के साथ रिटर्न प्रकारों से ठीक से मेल नहीं खाता है, तो रन-टाइम त्रुटियों को जन्म दे सकता है। मैं एक टेम्पलेट-आधारित दृष्टिकोण (या सी # में सामान्य पैरामीटर?) का उपयोग करने की सलाह दूंगा,
स्लीपब्लांक

0

रिकॉर्ड के लिए, ऑक्टेव रिटर्न तत्व स्केलर बनाम सरणी के अनुसार अलग-अलग परिणाम की अनुमति देता है।

x = min ([1, 3, 0, 2, 0])
   ⇒  x = 0

[x, ix] = min ([1, 3, 0, 2, 0])
   ⇒  x = 0
      ix = 3 (item index)

सीएफ भी विलक्षण मूल्य अपघटन


0

यह C ++ के लिए थोड़ा अलग है; मुझे नहीं पता कि क्या इसे सीधे रिटर्न टाइप द्वारा ओवरलोडिंग माना जाएगा। यह एक टेम्प्लेट स्पेशलाइजेशन से अधिक है जो कि तरीके से कार्य करता है।

util.h

#ifndef UTIL_H
#define UTIL_H

#include <string>
#include <sstream>
#include <algorithm>

class util {
public: 
    static int      convertToInt( const std::string& str );
    static unsigned convertToUnsigned( const std::string& str );
    static float    convertToFloat( const std::string& str );
    static double   convertToDouble( const std::string& str );

private:
    util();
    util( const util& c );
    util& operator=( const util& c );

    template<typename T>
    static bool stringToValue( const std::string& str, T* pVal, unsigned numValues );

    template<typename T>
    static T getValue( const std::string& str, std::size_t& remainder );
};

#include "util.inl"

#endif UTIL_H

util.inl

template<typename T>
static bool util::stringToValue( const std::string& str, T* pValue, unsigned numValues ) {
    int numCommas = std::count(str.begin(), str.end(), ',');
    if (numCommas != numValues - 1) {
        return false;
    }

    std::size_t remainder;
    pValue[0] = getValue<T>(str, remainder);

    if (numValues == 1) {
        if (str.size() != remainder) {
            return false;
        }
    }
    else {
        std::size_t offset = remainder;
        if (str.at(offset) != ',') {
            return false;
        }

        unsigned lastIdx = numValues - 1;
        for (unsigned u = 1; u < numValues; ++u) {
            pValue[u] = getValue<T>(str.substr(++offset), remainder);
            offset += remainder;
            if ((u < lastIdx && str.at(offset) != ',') ||
                (u == lastIdx && offset != str.size()))
            {
                return false;
            }
        }
    }
    return true;    
}

util.cpp

#include "util.h"

template<>
int util::getValue( const std::string& str, std::size_t& remainder ) {
    return std::stoi( str, &remainder );
} 

template<>
unsigned util::getValue( const std::string& str, std::size_t& remainder ) {
    return std::stoul( str, &remainder );
}

template<>
float util::getValue( const std::string& str, std::size_t& remainder ) {
    return std::stof( str, &remainder );
}     

template<>   
double util::getValue( const std::string& str, std::size_t& remainder ) {
    return std::stod( str, &remainder );
}

int util::convertToInt( const std::string& str ) {
    int i = 0;
    if ( !stringToValue( str, &i, 1 ) ) {
        std::ostringstream strStream;
        strStream << __FUNCTION__ << " Bad conversion of [" << str << "] to int";
        throw strStream.str();
    }
    return i;
}

unsigned util::convertToUnsigned( const std::string& str ) {
    unsigned u = 0;
    if ( !stringToValue( str, &u, 1 ) ) {
        std::ostringstream strStream;
        strStream << __FUNCTION__ << " Bad conversion of [" << str << "] to unsigned";
        throw strStream.str();
    }
    return u;
}     

float util::convertToFloat(const std::string& str) {
    float f = 0;
    if (!stringToValue(str, &f, 1)) {
        std::ostringstream strStream;
        strStream << __FUNCTION__ << " Bad conversion of [" << str << "] to float";
        throw strStream.str();
    }
    return f;
}

double util::convertToDouble(const std::string& str) {
    float d = 0;
    if (!stringToValue(str, &d, 1)) {
        std::ostringstream strStream;
        strStream << __FUNCTION__ << " Bad conversion of [" << str << "] to double";
        throw strStream.str();
    }
    return d;
}

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

प्रत्येक convertToTypeफ़ंक्शन फ़ंक्शन टेम्प्लेट को कॉल कर रहा है stringToValue()और यदि आप इस फ़ंक्शन टेम्प्लेट के कार्यान्वयन विवरण या एल्गोरिदम को देखते हैं, तो यह कॉलिंग है getValue<T>( param, param )और यह एक प्रकार को वापस कर रहा है और इसे एक में Tसंग्रहीत T*कर रहा हैstringToValue() फ़ंक्शन इसके मापदंडों में से एक के रूप फंक्शन टेम्पलेट ।

इस तरह से कुछ के अलावा; C ++ में वास्तव में रिटर्न प्रकार द्वारा फ़ंक्शन ओवरलोडिंग रिज़ॉल्यूशन के लिए एक तंत्र नहीं है। ऐसे अन्य निर्माण या तंत्र हो सकते हैं जिनके बारे में मुझे जानकारी नहीं है कि वापसी प्रकार से संकल्प अनुकरण कर सकते हैं।


-1

मुझे लगता है कि यह आधुनिक C ++ परिभाषा में एक GAP है ... क्यों?

int func();
double func();

// example 1. → defined
int i = func();

// example 2. → defined
double d = func();

// example 3. → NOT defined. error
void main() 
{
    func();
}

C ++ कंपाइलर उदाहरण "3" में त्रुटि क्यों नहीं दे सकता है और "1 + 2" उदाहरण में कोड को स्वीकार कर सकता है ??


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

-2

अधिकांश स्थिर भाषाएँ भी अब जेनरिक का समर्थन करती हैं, जो आपकी समस्या का समाधान करती हैं। जैसा कि पहले कहा गया है, पैरामीटर अलग होने के बिना, यह जानने का कोई तरीका नहीं है कि किसे कॉल करना है। इसलिए यदि आप ऐसा करना चाहते हैं, तो बस जेनरिक का उपयोग करें और इसे एक दिन कहें।


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

"रिटर्न प्रकार पर ओवरलोडिंग" के लिए एक चतुर रणनीति के लिए codeproject.com/KB/cpp/returnoverload.aspx देखें । मूल रूप से, एक फ़ंक्शन फ़ंक () को परिभाषित करने के बजाय, आप एक संरचनात्मक फ़ंक को परिभाषित करते हैं, इसे प्रत्येक उपयुक्त प्रकार के लिए एक ऑपरेटर () () और रूपांतरण देते हैं।
j_random_hacker

जे, जब आप फ़ंक्शन को कॉल करते हैं तो आप रिटर्न प्रकार को परिभाषित करते हैं। यदि इनपस भिन्न हैं, तो कोई समस्या नहीं है। यदि समान हैं, तो आपके पास एक सामान्य संस्करण हो सकता है जिसमें GetType () का उपयोग करके प्रकार के आधार पर कुछ तर्क हो सकते हैं।
चार्ल्स ग्राहम
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.