वापसी प्रकारों के साथ ओवरलोडिंग की अनुमति क्यों नहीं है? (कम से कम आमतौर पर इस्तेमाल की जाने वाली भाषाओं में)


9

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

मेरा मतलब कुछ इस तरह है:

 int method1 (int num)
 {

 }
 long method1 (int num)
 {

 }

ऐसा नहीं है कि यह प्रोग्रामिंग के लिए एक बड़ा मुद्दा है, लेकिन कुछ अवसरों पर मैंने इसका स्वागत किया है।

स्पष्ट रूप से उन भाषाओं के लिए कोई रास्ता नहीं होगा कि वे इस बात का समर्थन किए बिना कि किस विधि को कहा जा सकता है, लेकिन इसके लिए वाक्यविन्यास कुछ सरल हो सकता है जैसे कि [int] method1 (संख्या) या [long] method1 (संख्या) इस तरह से संकलक को पता चल जाएगा कि वह कौन सा होगा जिसे बुलाया जाएगा।

मुझे नहीं पता कि कंपाइलर कैसे काम करते हैं लेकिन ऐसा करना मुश्किल नहीं लगता है, इसलिए मुझे आश्चर्य है कि ऐसा कुछ क्यों नहीं किया जाता है जो आमतौर पर लागू नहीं होता है।

किन कारणों से ऐसा कुछ है जो समर्थित नहीं है?


हो सकता है कि आपका प्रश्न एक उदाहरण के साथ बेहतर होगा जहां दो रिटर्न प्रकारों के बीच निहित रूपांतरण मौजूद नहीं हैं - जैसे कक्षाएं Fooऔर Bar

खैर, ऐसी सुविधा क्यों उपयोगी होगी?
जेम्स यंगमैन

3
@JamesYoungman: उदाहरण के लिए तार को विभिन्न प्रकारों में पार्स करने के लिए, आप एक विधि पढ़ सकते हैं (स्ट्रिंग s), फ्लोट रीड (स्ट्रिंग s), और इसी तरह। विधि के प्रत्येक अतिभारित भिन्नता उपयुक्त प्रकार के लिए एक पार्स करता है।
जियोर्जियो

यह केवल वैधानिक रूप से टाइप की जाने वाली भाषाओं के साथ एक मुद्दा है। कई प्रकार के रिटर्न होने से जावास्क्रिप्ट या पायथन जैसी गतिशील रूप से टाइप की गई भाषाओं में बहुत नियमित है।
रोबोट

1
@StevenBurnap, उम, नहीं। उदाहरण के लिए जावास्क्रिप्ट के साथ, आप कार्य को ओवरलोडिंग बिल्कुल नहीं कर सकते। तो यह वास्तव में केवल भाषाओं के साथ एक मुद्दा है जो फ़ंक्शन नाम का समर्थन करता है ओवरलोडिंग।
डेविड अरनो

जवाबों:


19

यह प्रकार की जाँच को जटिल बनाता है।

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

var x = f();

given      f   : () -> int  [upward]
given      ()  : ()         [upward]
therefore  f() : int        [upward]
therefore  x   : int        [upward]

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

var x = parse("123");
print_int(x);

given      parse        : string -> T  [upward]
given      "123"        : string       [upward]
therefore  parse("123") : ∃T           [upward]
therefore  x            : ∃T           [upward]
given      print_int    : int -> ()    [upward]
therefore  print_int(x) : ()           [upward]
therefore  int -> ()    = ∃T -> ()     [downward]
therefore  ∃T           = int          [downward]
therefore  x            : int          [downward]

यहां, हमें xएक अनसुलझे प्रकार के चर के रूप में छोड़ने की आवश्यकता है ∃T, जहां हम इसके बारे में जानते हैं कि यह पार्स करने योग्य है। केवल बाद में, जब xएक ठोस प्रकार में प्रयोग किया जाता है, हम बाधा को सुलझाने और कि निर्धारित करने के लिए पर्याप्त जानकारी है ∃T = int, जो प्रकार की जानकारी प्रसारित नीचे में कॉल अभिव्यक्ति से वाक्य रचना पेड़ x

यदि हम इसके प्रकार को निर्धारित करने में विफल रहे x, तो या तो यह कोड अतिभारित हो जाएगा (इसलिए कॉलर प्रकार निर्धारित करेगा) या हमें अस्पष्टता के बारे में एक त्रुटि रिपोर्ट करनी होगी।

इससे, एक भाषा डिजाइनर निष्कर्ष निकाल सकता है:

  • यह कार्यान्वयन में जटिलता जोड़ता है।

  • यह पैथोलॉजिकल मामलों में धीमी गति से टाइपकास्ट करता है, इसलिए तेजी से।

  • अच्छी त्रुटि संदेश उत्पन्न करना कठिन है।

  • यह यथास्थिति से बहुत अलग है।

  • मुझे इसे लागू करने का मन नहीं है।


1
इसके अलावा: यह समझना बहुत कठिन होगा कि कुछ मामलों में आपके कंपाइलर ऐसे विकल्प बनाएंगे जो प्रोग्रामर को बिल्कुल उम्मीद नहीं थी, जिससे बग्स को ढूंढना मुश्किल हो जाएगा।
gnasher729

1
@ gnasher729: मैं असहमत हूं। मैं नियमित रूप से हास्केल का उपयोग करता हूं, जिसमें यह विशेषता है, और मुझे कभी भी इसके अधिभार के विकल्प से काट नहीं लिया गया है। अगर कुछ अस्पष्ट है, तो यह मुझे एक प्रकार का एनोटेशन जोड़ने के लिए मजबूर करता है। और मैंने अभी भी अपनी भाषा में पूर्ण प्रकार के इंजेक्शन को लागू करने के लिए चुना क्योंकि यह अविश्वसनीय रूप से उपयोगी है। यह जवाब मुझे शैतान के वकील का था।
जॉन पूर्डी

4

क्योंकि यह अस्पष्ट है। उदाहरण के रूप में C # का उपयोग करना:

var foo = method(42);

हमें किस अधिभार का उपयोग करना चाहिए?

ठीक है, शायद वह थोड़ा अनुचित था। कंपाइलर यह पता नहीं लगा सकता है कि यदि हम इसे आपकी काल्पनिक भाषा में नहीं बताते हैं तो किस प्रकार का उपयोग करना है। तो, आपकी भाषा में निहित टाइपिंग असंभव है और इसके साथ गुमनाम तरीके और लिनक भी जाते हैं ...

इसके बारे में क्या खयाल है? (बिंदु को स्पष्ट करने के लिए थोड़े से पुनर्निर्धारित हस्ताक्षर।)

short method(int num) { ... }
int method(int num) { ... }

....

long foo = method(42);

क्या हमें intअधिभार, या अधिभार का उपयोग करना चाहिए short? हमें आसानी से पता नहीं है, हमें इसे आपके [int] method1(num)सिंटैक्स के साथ निर्दिष्ट करना होगा । जो थोड़े दर्द के लिए है और लिखने के लिए ईमानदार है।

long foo = [int] method(42);

बात यह है, यह आश्चर्यजनक रूप से सी # में एक सामान्य विधि के समान वाक्यविन्यास है।

long foo = method<int>(42);

(C ++ और Java में समान विशेषताएं हैं।)

संक्षेप में, भाषा डिजाइनरों ने पार्सिंग को सरल बनाने और बहुत अधिक शक्तिशाली भाषा सुविधाओं को सक्षम करने के लिए समस्या को अलग तरीके से हल करने के लिए चुना।

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


जेनेरिक के बारे में अच्छी बात है, हालांकि आप दिखावटी हैं shortऔर int
रॉबर्ट हार्वे

हाँ @RobertHarvey तुम सही हो। मैं एक उदाहरण के लिए इस मुद्दे को स्पष्ट करने के लिए संघर्ष कर रहा था। यह बेहतर काम करेगा यदि methodएक छोटा या अंतर लौटाया जाए, और प्रकार को लंबे समय तक परिभाषित किया गया।
रबरडक

यह थोड़ा बेहतर लगता है।
रबरडक

मैं आपकी दलीलें नहीं खरीदता कि आपके पास रिटर्न टाइप ओवरलोडिंग वाली भाषा में टाइप इंट्रेंस, अनाम सबरूटीन्स या मोनड कॉम्प्रिहेंशन नहीं हो सकता। हास्केल करता है, और हास्केल के पास तीनों हैं। इसमें पैरामीट्रिक बहुरूपता भी है। अपनी बात के बारे में long/ int/ shortsubtyping की जटिलताओं और / या वापसी प्रकार से अधिक भार के बारे में की तुलना में निहित रूपांतरण के बारे में अधिक है। आखिरकार, C ++, Java, C and, और कई अन्य लोगों में उनकी वापसी के प्रकार पर नंबर शाब्दिक रूप से ओवरलोड किया जाता है, और यह समस्या पेश नहीं करता है। आप बस एक नियम बना सकते हैं: जैसे सबसे विशिष्ट / सामान्य प्रकार चुनें।
जोर्ग डब्ल्यू मित्तग

@ JörgWMittag मेरी बात यह नहीं थी कि यह असंभव है, बस यह अनावश्यक रूप से जटिल बनाता है।
रबरडक

0

सभी भाषा सुविधाएँ जटिलता को जोड़ती हैं, इसलिए उन्हें अपरिहार्य गोच, कोने के मामलों, और उपयोगकर्ता के भ्रम का औचित्य साबित करने के लिए पर्याप्त लाभ प्रदान करना होता है। अधिकांश भाषाओं के लिए, यह इसे उचित ठहराने के लिए पर्याप्त लाभ प्रदान नहीं करता है।

अधिकांश भाषाओं में, आप उम्मीद करेंगे कि अभिव्यक्ति method1(2)का एक निश्चित प्रकार और अधिक या कम पूर्वानुमानित वापसी मूल्य हो। लेकिन अगर आप रिटर्न वैल्यू पर ओवरलोडिंग की अनुमति देते हैं, तो इसका मतलब है कि यह बताना असंभव है कि उस संदर्भ में सामान्य रूप से उसके आसपास के संदर्भ पर विचार किए बिना इसका क्या मतलब है। विचार करें कि क्या होता है जब आपके पास एक unsigned long long foo()विधि होती है जिसका कार्यान्वयन किसके साथ समाप्त होता है return method1(2)? क्या उस कॉल को- longअधिभोग अधिभार या- intअधिभार अधिभार या बस एक संकलक त्रुटि देना चाहिए?

साथ ही, यदि आपको रिटर्न प्रकार की व्याख्या करके संकलक की मदद करनी है, तो न केवल आप अधिक सिंटैक्स का आविष्कार कर रहे हैं (जो कि सभी को सुविधा प्रदान करने की उपरोक्त लागतों को बढ़ाता है), लेकिन आप प्रभावी रूप से एक ही काम कर रहे हैं एक "सामान्य" भाषा में दो अलग-अलग नाम वाले तरीके। है [long] method1(2)की तुलना में अधिक सहज ज्ञान युक्त long_method1(2)?


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


2
"सभी कार्यों को शुद्ध और प्रासंगिक रूप से पारदर्शी होने की आवश्यकता के साथ": यह रिटर्न प्रकार को ओवरलोडिंग कैसे आसान बनाता है?
जियोर्जियो

@ जियोर्जियो यह नहीं करता है - जंग फ़ंक्शन शुद्धता को लागू नहीं करता है और यह अभी भी वापसी प्रकार ओवरलोडिंग कर सकता है (हालांकि उसके जंग में ओवरलोडिंग अन्य भाषाओं की तुलना में बहुत अलग है (आप केवल टेम्पलेट्स का उपयोग करके अधिभार कर सकते हैं)
ईडन आर्ये

[लंबे] और [int] भाग के पास विधि को स्पष्ट रूप से कॉल करने का एक तरीका था, ज्यादातर मामलों में इसे कैसे बुलाया जाना चाहिए यह चर के प्रकार से सीधे अनुमान लगाया जा सकता है जिसे विधि का निष्पादन सौंपा गया है।
user2638180

0

यह है स्विफ्ट में उपलब्ध है और ठीक वहाँ काम करता है। जाहिर है कि आपके पास दोनों तरफ अस्पष्ट प्रकार नहीं हो सकते हैं, इसलिए इसे बाईं ओर जाना होगा।

मैं एक साधारण सांकेतिक शब्दों में बदलना / डिकोड एपीआई में इसका इस्तेमाल किया ।

public protocol HierDecoder {
  func dech() throws -> String
  func dech() throws -> Int
  func dech() throws -> Bool

इसका मतलब है कि कॉल जहां पैरामीटर प्रकार के रूप में जाना जाता है, जैसे कि initएक वस्तु, बहुत सरलता से काम करते हैं:

    private static let typeCode = "ds"
    static func registerFactory() {
        HierCodableFactories.Register(key:typeCode) {
            (from) -> HierCodable in
            return try tgDrawStyle(strokeColor:from.dech(), fillColor:from.dechOpt(), lineWidth:from.dech(), glowWidth: from.dech())
        }
    }
    func typeKey() -> String { return tgDrawStyle.typeCode }
    func encode(to:HierEncoder) {
        to.ench(strokeColor)
        to.enchOpt(fillColor)
        to.ench(lineWidth)
        to.ench(glowWidth)
    }

यदि आप निकट ध्यान दे रहे हैं, तो आप dechOptऊपर कॉल को नोटिस करेंगे । मुझे पता चला कि हार्ड ड्राइव उसी फ़ंक्शन नाम को ओवरलोड कर रहा है, जहां विभेदक एक वैकल्पिक लौटा रहा था, त्रुटि का भी खतरा था क्योंकि कॉलिंग संदर्भ एक उम्मीद पेश कर सकता है यह एक वैकल्पिक था।


-5
int main() {
    auto var1 = method1(1);
}

उस मामले में कंपाइलर a) कॉल को अस्वीकार कर सकता है क्योंकि यह अस्पष्ट है b) पहले / अंतिम एक c को चुनें) टाइप को छोड़ दें var1और टाइप इंट्रेंस के साथ आगे बढ़ें और जैसे ही कुछ अन्य एक्सप्रेशन का var1उपयोग करने के प्रकार को निर्धारित करता है कि चयन के लिए सही कार्यान्वयन। नीचे की रेखा पर, एक ऐसा मामला दिखा रहा है, जहां प्रकार का अनुमान गैर-तुच्छ है, शायद ही कभी किसी बिंदु को साबित करता है, उस प्रकार का अनुमान आमतौर पर गैर-तुच्छ है।
back2dos

1
मजबूत तर्क नहीं। उदाहरण के लिए, जंग प्रकार का भारी उपयोग करता है, और कुछ मामलों में, विशेष रूप से जेनरिक के साथ, आपको यह नहीं बता सकता कि आपको किस प्रकार की आवश्यकता है। इस तरह के मामलों में, आपको केवल प्रकार के अनुमान पर भरोसा करने के बजाय स्पष्ट रूप से टाइप करना होगा।
8bittree

1
उह ... जो एक अतिभारित रिटर्न प्रकार प्रदर्शित नहीं करता है। method1किसी विशेष प्रकार को वापस करने के लिए घोषित किया जाना चाहिए।
रोबोट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.