क्या डायनामिक रूप से टाइप की गई भाषा में एक ही फ़ंक्शन से विभिन्न डेटा प्रकारों को वापस करना एक बुरा विचार है?


65

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

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

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


संपादित करें : मैं अपना उदाहरण निकालने जा रहा हूं (जब तक मैं एक बेहतर सोच सकता हूं)। मुझे लगता है कि यह लोगों को एक बिंदु पर जवाब देने के लिए स्टीयरिंग है जिसे मैं बनाने की कोशिश नहीं कर रहा हूं।


त्रुटि के मामले में अपवाद क्यों नहीं?
ट्रूविल

1
@TrueWill मुझे पता है कि अगले वाक्य में।
डेनियल कपलान

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

3
उल्लेख नहीं किया गया है, लेकिन एक पैरामीटर के रूप में रिटर्न-प्रकार लेने वाले कार्यों के कई उदाहरण (जावा जेनरिक में भी) हैं; उदाहरण के लिए आम लिस्प में हमारे पास (coerce var 'string)पैदावार stringया (concatenate 'string this that the-other-thing)इसी तरह है। मैंने जैसी बातें लिखी हैं ThingLoader.getThingById (Class<extends FindableThing> klass, long id)। और, वहाँ, मैं केवल कुछ वापस कर सकता हूँ जो आपके द्वारा मांगे गए उपवर्गों में से loader.getThingById (SubclassA.class, 14)हो सकता है : जो SubclassBकि वापस लौटता है SubclassA...
BRPocock

1
डायनामिक टाइप की गई भाषाएं फिल्म द मैट्रिक्स में स्पून की तरह हैं । चम्मच को एक स्ट्रिंग या संख्या के रूप में परिभाषित करने का प्रयास न करें । यह असंभव होगा। इसके बजाय ... केवल सच्चाई को समझने की कोशिश करें। कि कोई चम्मच नहीं है ।
रिएक्टगुलर

जवाबों:


42

अन्य उत्तरों के विपरीत, ऐसे मामले हैं जहां विभिन्न प्रकारों को वापस करना स्वीकार्य है।

उदाहरण 1

sum(2, 3)  int
sum(2.1, 3.7)  float

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

var sum = function (a, b) {
    return a + b;
};

समान फ़ंक्शन, विभिन्न प्रकार के रिटर्न मूल्य।

उदाहरण 2

कल्पना कीजिए कि आपको OpenID / OAuth घटक से प्रतिक्रिया मिलती है। कुछ OpenID / OAuth प्रदाताओं में अधिक जानकारी हो सकती है, जैसे कि व्यक्ति की आयु।

var user = authProvider.findCurrent();
// user is now:
// {
//     provider: 'Facebook',
//     name: {
//         firstName: 'Hello',
//         secondName: 'World',
//     },
//     email: 'hello.world@example.com',
//     age: 27
// }

दूसरों के पास न्यूनतम होगा, क्या यह एक ईमेल पता या छद्म नाम होगा।

var user = authProvider.findCurrent();
// user is now:
// {
//     provider: 'Google',
//     email: 'hello.world@example.com'
// }

फिर से, एक ही कार्य, विभिन्न परिणाम।

यहां, विभिन्न प्रकारों को वापस करने का लाभ विशेष रूप से उस संदर्भ में महत्वपूर्ण है जहां आप प्रकारों और इंटरफेस के बारे में परवाह नहीं करते हैं, लेकिन वास्तव में क्या वस्तुएं हैं। उदाहरण के लिए, आइए कल्पना करें कि एक वेबसाइट में परिपक्व भाषा है। तो findCurrent()इस तरह इस्तेमाल किया जा सकता है:

var user = authProvider.findCurrent();
if (user.age || 0 >= 16) {
    // The person can stand mature language.
    allowShowingContent();
} else if (user.age) {
    // OpenID/OAuth gave the age, but the person appears too young to see the content.
    showParentalAdvisoryRequestedMessage();
} else {
    // OpenID/OAuth won't tell the age of the person. Ask the user himself.
    askForAge();
}

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

var age;
if (['Facebook', 'Yahoo', 'Blogger', 'LiveJournal'].contains(user.provider)) {
    age = user.age;
}

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

17
अपने विशिष्ट उदाहरण के लिए, हास्केल पर विचार करें sum :: Num a => [a] -> a:। आप किसी भी चीज़ की एक सूची लिख सकते हैं जो एक संख्या है। जावास्क्रिप्ट के विपरीत, यदि आप कुछ ऐसा योग बनाने का प्रयास करते हैं जो संख्या नहीं है, तो संकलन समय पर त्रुटि पकड़ी जाएगी।
एंड्रेस एफ।

3
@ मेनमा इन स्काला, Iterator[A]में विधि है def sum[B >: A](implicit num: Numeric[B]): B, जो फिर से किसी भी प्रकार की संख्या को योग करने की अनुमति देती है और संकलन समय पर जांच की जाती है।
पेट्र पुडलक

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

2
मैं विशेष रूप से आपके दूसरे उदाहरण से प्रभावित नहीं हूं। वे दो वस्तुएं एक ही वैचारिक "प्रकार" हैं, यह सिर्फ इतना है कि कुछ उदाहरणों में कुछ क्षेत्रों को परिभाषित या आबाद नहीं किया जाता है। आप nullमान सकते हैं कि मूल्यों के साथ एक सांख्यिकीय रूप से टाइप की गई भाषा में भी ठीक है ।
हारून

31

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

कई मामलों में, हालांकि, कविता और कारण है कि किस प्रकार को लौटाया जाता है और प्रभाव स्थैतिक प्रकार प्रणालियों में ओवरलोडिंग या पैरामीट्रिक बहुरूपता के समान है। दूसरे शब्दों में, परिणाम प्रकार है उम्मीद के मुताबिक, यह सिर्फ काफी के रूप में सरल नहीं व्यक्त करने के लिए है।

लेकिन ध्यान दें कि अन्य कारण हो सकते हैं कि कोई विशिष्ट फ़ंक्शन बुरी तरह से डिज़ाइन किया गया है: उदाहरण के लिए, sumअमान्य इनपुट पर गलत तरीके से लौटने वाला एक फ़ंक्शन मुख्य रूप से एक बुरा विचार है क्योंकि यह रिटर्न वैल्यू बेकार है और त्रुटि-प्रवण (0 <-> गलत भ्रम) है।


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

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

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

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

4
मुझे नहीं पता कि यह "शून्य बनाम बाकी सब" तर्क में क्यों बदल गया। मैं केवल यह इंगित कर रहा था कि NaNमूल्य वास्तव में एक अलग रिटर्न प्रकार नहीं है और (बी) में अच्छी तरह से परिभाषित फ्लोटिंग-पॉइंट शब्दार्थ है, और इसलिए वास्तव में एक वेरिएबल-टाइप किए गए रिटर्न मान के एनालॉग के रूप में योग्य नहीं है। यह वास्तव में पूर्णांक अंकगणित में शून्य से अलग नहीं है; यदि शून्य "गलती से" आपकी गणना में फिसल जाता है, तो आप अक्सर परिणाम के रूप में शून्य या एक विभाजन-से-शून्य त्रुटि के साथ समाप्त होने की संभावना रखते हैं। IEEE फ़्लोटिंग पॉइंट द्वारा परिभाषित "अनन्तता" मूल्य भी बुरे हैं?
Aaronaught

26

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

विभिन्न प्रकारों को वापस करते समय समझ में आता है

उदाहरण के लिए यह विधि समझ में आती है:

def load_file(file): 
    if something: 
       return ['a ', 'list', 'of', 'strings'] 
    return open(file, 'r')

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

आप सशर्त लौट सकते हैं listया tuple( tupleअजगर में एक अपरिवर्तनीय सूची है)।

औपचारिक रूप से भी कर रहे हैं:

def do_something():
    if ...: 
        return None
    return something_else

या:

function do_something(){
   if (...) return null; 
   return sth;
}

विभिन्न प्रकार के रिटर्न, जैसे कि अजगर Noneऔर जावास्क्रिप्ट दोनों nullअपने स्वयं के प्रकार हैं।

इन सभी उपयोग मामलों में स्थिर भाषाओं में उनके समकक्ष होंगे, फ़ंक्शन सिर्फ एक उचित इंटरफ़ेस वापस करेगा।

सशर्त रूप से विभिन्न एपीआई के साथ वस्तुओं को वापस करना एक अच्छा विचार है

क्या अलग एपीआई वापस करना एक अच्छा विचार है, आईएमओ ज्यादातर मामलों में इसका कोई मतलब नहीं है। केवल समझदार उदाहरण जो मन में आता है वह @MainMa के पास कुछ है : जब आपका एपीआई अलग-अलग राशि प्रदान कर सकता है, तो उपलब्ध होने पर अधिक विवरण वापस करने के लिए समझ में आ सकता है।


4
अच्छा उत्तर। वर्थ ध्यान में रखते हुए कि जावा / स्टेटिकली समतुल्य समकक्ष को एक विशिष्ट ठोस प्रकार के बजाय एक इंटरफ़ेस रिटर्न करना है, जिसमें एपीआई / एब्स्ट्रक्शन का प्रतिनिधित्व करने वाला इंटरफ़ेस है।
मीकेरा

1
मुझे लगता है कि आप पायथन में हैं, एक सूची में और एक ट्यूपल अलग-अलग "प्रकार" के हो सकते हैं, लेकिन वे एक ही "बतख प्रकार" के होते हैं, अर्थात वे संचालन के एक ही सेट का समर्थन करते हैं। और इस तरह के मामले ठीक उसी तरह से हैं क्योंकि बतख टाइपिंग शुरू की गई है। आप जावा में भी लंबे x = getInt () कर सकते हैं।
करबर

"विभिन्न प्रकार लौटना" का अर्थ है "विभिन्न एपीआई के साथ वस्तुओं को वापस करना"। (कुछ भाषाएं जिस तरह से ऑब्जेक्ट को एपीआई के एक मूलभूत हिस्से का निर्माण करती हैं, कुछ नहीं करते हैं; यह इस बात का है कि टाइप सिस्टम कितना अभिव्यंजक है।) आपकी सूची / फ़ाइल उदाहरण में, do_fileकिसी भी तरह से स्ट्रिंग्स के चलने योग्य बनाता है।
गिल्स

1
उस पायथन उदाहरण में, आप iter()सूची और फ़ाइल दोनों पर कॉल कर सकते हैं, यह सुनिश्चित करने के लिए कि परिणाम केवल दोनों मामलों में एक पुनरावृत्त के रूप में उपयोग किया जा सकता है।
रेमकोगर्लिच

1
वापसी None or somethingPyPy, Numba, Pyston और अन्य जैसे उपकरणों द्वारा किए गए प्रदर्शन अनुकूलन के लिए एक हत्यारा है। यह पायथन-इस्म में से एक है जो अजगर को इतना तेज नहीं बनाता है।
मैट

9

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

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

लेकिन यह कह रही है "मैं इस का उपयोग करने के लिए एक बनाने के लिए जा रहा हूँ के लिए एक छोटी कदम है कारखाने पैटर्न और वापसी" या तो fooया barया bazसमारोह की मनोदशा पर निर्भर करता है। डिबगिंग यह एक दुःस्वप्न बन जाएगा, जब कॉलर उम्मीद करता है fooलेकिन दिया गया था bar

इसलिए मुझे नहीं लगता कि आप बंद दिमाग वाले हैं। आप भाषा की विशेषताओं का उपयोग करने में उचित रूप से सतर्क हैं।

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


6

जावा में जेनरिक का उपयोग करने से आप स्थिर प्रकार की सुरक्षा को बनाए रखते हुए एक अलग प्रकार वापस कर सकते हैं। आप बस उस प्रकार को निर्दिष्ट करते हैं जिसे आप फ़ंक्शन कॉल के सामान्य प्रकार के पैरामीटर में वापस करना चाहते हैं।

आप जावास्क्रिप्ट में एक समान दृष्टिकोण का उपयोग कर सकते हैं, बेशक, एक खुला प्रश्न है। चूंकि जावास्क्रिप्ट एक गतिशील रूप से टाइप की जाने वाली भाषा है, इसलिए objectयह स्पष्ट विकल्प की तरह लगता है।

यदि आप जानना चाहते हैं कि गतिशील रूप से टाइप की गई भाषा में काम करने के लिए डायनामिक रिटर्न परिदृश्य कहाँ काम कर सकता है, तो dynamicC # में कीवर्ड को देखें। Rob Conery कीवर्ड का उपयोग करके कोड की 400 लाइनों में ऑब्जेक्ट-रिलेशनल मैपर को सफलतापूर्वक लिखने में सक्षम था dynamic

बेशक, सभी dynamicवास्तव में objectकुछ रनटाइम प्रकार की सुरक्षा के साथ एक चर लपेटता है ।


4

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


4

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

यहां आप जो प्रस्ताव देते हैं, वह आपत्तिजनक हिस्सा है। अगर मुझे नहीं पता कि किस प्रकार का रिटर्न दिया गया है, तो मैं तुरंत रिटर्न वैल्यू का उपयोग नहीं कर सकता। मुझे इसके बारे में कुछ "खोज" करना है।

total = sum_of_array([20, 30, 'q', 50])
if (type_of(total) == Boolean) {
  display_error(...)
} else {
  record_number(total)
}

अक्सर कोड में इस तरह का स्विच बस बुरा अभ्यास है। यह कोड को पढ़ने में कठिन बनाता है। इस उदाहरण में, आप देखते हैं कि अपवाद मामलों को फेंकना और पकड़ना लोकप्रिय क्यों है। दूसरा तरीका रखो: यदि आपका कार्य वह नहीं कर सकता जो वह कहता है कि वह करता है, तो उसे सफलतापूर्वक नहीं लौटना चाहिए । यदि मैं आपका कार्य कहता हूं, तो मैं यह करना चाहता हूं:

total = sum_of_array([20, 30, 'q', 50])
display_number(total)

क्योंकि पहली पंक्ति सफलतापूर्वक लौटती है, मैं मानता हूं कि totalवास्तव में सरणी का योग है। यदि यह सफलतापूर्वक वापस नहीं आता है, तो हम मेरे कार्यक्रम के किसी अन्य पृष्ठ पर जाते हैं।

आइए एक और उदाहरण का उपयोग करें जो त्रुटियों के प्रचार के बारे में नहीं है। शायद sum_of_array स्मार्ट बनने और कुछ मामलों में मानव-पठनीय स्ट्रिंग वापस करने की कोशिश करता है, जैसे "यह मेरा लॉकर संयोजन है!" अगर और केवल अगर सरणी [11,7,19] है। मुझे एक अच्छा उदाहरण सोचने में परेशानी हो रही है। वैसे भी, एक ही समस्या लागू होती है। इसके साथ कुछ भी करने से पहले आपको रिटर्न वैल्यू का निरीक्षण करना होगा:

total = sum_of_array([20, 30, 40, 50])
if (type_of(total) == String) {
  write_message(total)
} else {
  record_number(total)
}

आप यह तर्क दे सकते हैं कि पूर्णांक या फ्लोट को वापस करने के लिए यह कार्य उपयोगी होगा, उदा:

sum_of_array(20, 30, 40) -> int
sum_of_array(23.45, 45.67, 67.789044) -> float

लेकिन वे परिणाम भिन्न प्रकार के नहीं हैं, जहाँ तक आप चिंतित हैं। आप उन दोनों को संख्या के रूप में मानने वाले हैं, और आप सभी की परवाह करते हैं। तो sum_of_array संख्या प्रकार लौटाता है। यह बहुरूपता के बारे में है।

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


क्षमा करें, मैंने अपने खराब उदाहरण से आपको भटका दिया। भूल जाओ मैंने पहली बार में इसका उल्लेख किया था। आपका पहला पैराग्राफ बिंदु पर है। मुझे आपका दूसरा उदाहरण भी पसंद है।
डैनियल कपलान

4

वास्तव में, यह एक असामान्य रूप से टाइप की गई भाषा में भी विभिन्न प्रकारों को वापस करने के लिए बिल्कुल असामान्य नहीं है। इसलिए हमारे पास संघ प्रकार हैं, उदाहरण के लिए।

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

कई भाषाओं में, त्रुटि की स्थिति को उप-प्रकार के रूप में तैयार किया जाता है, जिसके परिणामस्वरूप परिणाम प्रकार या त्रुटि प्रकार होता है। उदाहरण के लिए, स्काला में:

def transferMoney(amount: Decimal): Either[String, Decimal]

यह एक बेवकूफी भरा उदाहरण है। वापसी प्रकार का अर्थ है "या तो एक स्ट्रिंग या एक दशमलव लौटें"। कन्वेंशन द्वारा, बाएं प्रकार त्रुटि प्रकार है (इस मामले में, त्रुटि संदेश के साथ एक स्ट्रिंग) और सही प्रकार परिणाम प्रकार है।

यह अपवादों के समान है, इस तथ्य को छोड़कर कि अपवाद भी नियंत्रण प्रवाह निर्माण हैं। वे वास्तव में, अभिव्यंजक शक्ति के बराबर हैं GOTO


जावा को वापस करने का तरीका अजीब लगता है। " एक अपवाद लौटें " ... हम्म
ज्ञानी

3
जावा में एक विधि का एक अपवाद एक संभावित परिणाम है। असल में, मैं एक चौथा प्रकार भूल गया: Unit(एक विधि को वापस करने की आवश्यकता नहीं है)। सच है, आप वास्तव में returnकीवर्ड का उपयोग नहीं करते हैं , लेकिन यह एक परिणाम है जो फिर भी विधि से वापस आता है। चेक किए गए अपवादों के साथ, यह स्पष्ट रूप से प्रकार के हस्ताक्षर में उल्लिखित है।
जोर्ग डब्ल्यू मित्तग

समझा। आपकी बात में कुछ खूबियां हैं, लेकिन जिस तरह से इसे प्रस्तुत किया गया है वह इसे सम्मोहक नहीं बनाता है ... बल्कि विपरीत है
gnat

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

4

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

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

एक स्ट्रिंग या पूर्णांक वापस करने के बजाय, एक बेहतर उदाहरण यह हो सकता है कि वह स्प्रिंकलर सिस्टम या बिल्ली लौटाए। यह ठीक है अगर सभी कॉलिंग कोड करने जा रहे हैं, तो कॉल फ़ंक्शन हैInQuestion.hiss ()। प्रभावी रूप से आपके पास एक अंतर्निहित इंटरफ़ेस है जिसे कॉलिंग कोड उम्मीद कर रहा है, और एक गतिशील रूप से टाइप की गई भाषा आपको इंटरफ़ेस स्पष्ट करने के लिए मजबूर नहीं करेगी।

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


3

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

function ensure_fields($consideration)
{
        $args = func_get_args();
        foreach ( $args as $a ) {
                if ( !is_string($a) ) {
                        return NULL;
                }
                if ( !isset($consideration[$a]) || $consideration[$a]=='' ) {
                        return FALSE;
                }
        }

        return TRUE;
}

फ़ंक्शन मुख्य रूप से BOOLEAN देता है, हालांकि यह अमान्य इनपुट पर NULL देता है। ध्यान दें कि PHP 5.3 के बाद से, सभी आंतरिक PHP फ़ंक्शन इस तरह से भी व्यवहार करते हैं । इसके अतिरिक्त, कुछ आंतरिक PHP फ़ंक्शन नाममात्र इनपुट पर FALSE या INT लौटाते हैं, देखें:

strpos('Hello', 'e');  // Returns INT(1)
strpos('Hello', 'q');  // Returns BOOL(FALSE)

4
और यही कारण है कि मैं PHP से नफरत करता हूं। खैर, कारणों में से एक, वैसे भी।
Aaronaught

1
एक नीचता क्योंकि किसी को वह भाषा पसंद नहीं है जिसे मैं पेशेवर रूप से विकसित करता हूं?!? रुको जब तक उन्हें पता न चले कि मैं यहूदी हूँ! :)
14 फरवरी को dotancohen

3
हमेशा यह मत समझो कि टिप्पणी करने वाले लोग और अपमान करने वाले लोग वही लोग हैं।
Aaronaught

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

1
इसके अलावा, यदि आप nullत्रुटि पर लौटते हैं , तो कृपया कृपया डॉकब्लॉक (जैसे @return boolean|null) में स्पष्ट करें , इसलिए यदि मैं किसी दिन आपके कोड में आता हूं तो मुझे फ़ंक्शन / विधि बॉडी की जांच नहीं करनी होगी।
स्क्रिप्ट

3

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

जावा 1.4

public static Boolean getBoolean(String property){
    return (Boolean) properties.getProperty(property);
}
public static Integer getInt(String property){
    return (Integer) properties.getProperty(property);
}

जावा 1.5+

public static <T> getValue(String property, Class<T> clazz) throws WhateverCheckedException{
    return clazz.getConstructor(String.class).newInstance(properties.getProperty(property));
}
//the call will be
Boolean b = getValue("useProxy",Boolean.class);
Integer b = getValue("proxyPort",Integer.class);

एक गतिशील टाइप की गई भाषा में, चूँकि आपके पास संकलन के समय कोई टाइपफ़ेक्टी नहीं है, आप एक ही कोड लिखने के लिए बिल्कुल स्वतंत्र हैं जो कई प्रकारों के लिए काम करता है। चूंकि इस समस्या को हल करने के लिए एक सांख्यिकीय रूप से टाइप की गई भाषा में जेनरिक को पेश किया गया था, यह स्पष्ट रूप से एक संकेत है कि एक फ़ंक्शन लिखना जो एक गतिशील भाषा में विभिन्न प्रकारों को वापस करता है, एक बुरा विचार नहीं है।


स्पष्टीकरण के बिना एक और गिरावट! धन्यवाद एसई समुदाय!
थर्मज

2
एक सहानुभूति +1 है। आपको अधिक स्पष्ट और सीधे उत्तर के साथ अपना उत्तर खोलने का प्रयास करना चाहिए, और विभिन्न उत्तरों पर टिप्पणी करने से बचना चाहिए। (मैं आपको एक और +1 दूंगा, क्योंकि मैं आपसे सहमत हूं, लेकिन मेरे पास केवल एक देने के लिए है।)
डग

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

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

1
बुरा मत मानना, @atherz डाउनवोट्स अक्सर लेखक के मुकाबले पाठक के बारे में अधिक कहते हैं।
कार्ल बेवेलफेल्ट

2

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


1

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

my @now = localtime();

तब @now एक ऐरे वेरिएबल है (जो कि @ का मतलब है), और इसमें एक ऐरे (40, 51, 20, 9, 0, 109, 5, 8, 0) जैसे ऐरे शामिल होंगे।

यदि इसके बजाय आप फ़ंक्शन को इस तरह से कॉल करते हैं, जहां इसका परिणाम एक स्केलर होना होगा, ($ चर स्केलर्स हैं):

my $now = localtime();

तब यह पूरी तरह से अलग कुछ करता है: $ अब कुछ इस तरह होगा "शुक्र जनवरी 9 20:51:40 2009"।

एक और उदाहरण मैं सोच सकता हूं कि आरईएसटी एपीआई को लागू करने में, जहां लौटाया गया का प्रारूप इस बात पर निर्भर करता है कि ग्राहक क्या चाहता है। जैसे, HTML, या JSON, या XML। हालाँकि तकनीकी रूप से वे सभी बाइट्स की धाराएँ हैं, लेकिन विचार समान है।


आप इसका उल्लेख विशिष्ट तरीके से करना चाहते हैं - perl - wantarray ... और हो सकता है कि कुछ चर्चा का एक लिंक अगर इसके अच्छे या बुरे - PerlMonks पर इस्तेमाल किए जाने वाले विचारक का उपयोग

संयोग से, मैं जावा रेस्ट एपीआई के साथ काम कर रहा हूं। मैंने एक संसाधन के लिए XML या JSON पर वापस जाना संभव बना दिया। उस मामले में सबसे कम आम भाजक प्रकार एक है String। अब लोग रिटर्न टाइप पर दस्तावेज मांग रहे हैं। जावा उपकरण अगर मैं एक कक्षा में लौटता हूं तो यह स्वचालित रूप से उत्पन्न कर सकता है, लेकिन क्योंकि मैंने चुना है कि मैं Stringदस्तावेज़ स्वचालित रूप से उत्पन्न नहीं कर सकता। कहानी के अधूरेपन / नैतिकता में, मेरी इच्छा है कि मैं प्रति विधि एक प्रकार लौटाऊं।
डैनियल कपलान

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

1

डायनामिक-लैंड में यह सब डक-टाइपिंग के बारे में है। सबसे जिम्मेदार उजागर / सार्वजनिक-सामना करने वाली बात यह है कि संभावित रूप से विभिन्न प्रकार के आवरण में लपेटना है जो उन्हें समान इंटरफ़ेस देता है।

function ThingyWrapper(thingy){ //a function constructor (class-like thingy)

    //thingy is effectively private and persistent for ThingyWrapper instances

    if(typeof thingy === 'array'){
        this.alertItems = function(){
            thingy.forEach(function(el){ alert(el); });
        }
    }
    else {
        this.alertItems = function(){
            for(var x in thingy){ alert(thingy[x]); }
        }
    }
}

function gimmeThingy(){
    var
        coinToss = Math.round( Math.random() ),//gives me 0 or 1
        arrayThingy = [1,2,3],
        objectThingy = { item1:1, item2:2, item3:3 }
    ;

    //0 dynamically evaluates to false in JS
    return new ThingyWrapper( coinToss ? arrayThingy : objectThingy );
}

gimmeThingy().alertItems(); //should be same every time except order of numbers - maybe

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

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

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