"केवल एक वापसी" की धारणा कहां से आई?


1055

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

if (condition)
   return 42;
else
   return 97;

" यह बदसूरत है, आपको एक स्थानीय चर का उपयोग करना होगा! "

int result;
if (condition)
   result = 42;
else
   result = 97;
return result;

यह 50% कोड ब्लोट कैसे प्रोग्राम को समझने में आसान बनाता है? व्यक्तिगत रूप से, मुझे यह कठिन लगता है, क्योंकि राज्य की जगह सिर्फ एक और चर से बढ़ी है जिसे आसानी से रोका जा सकता था।

बेशक, आम तौर पर मैं सिर्फ लिखूंगा:

return (condition) ? 42 : 97;

लेकिन कई प्रोग्रामर सशर्त ऑपरेटर से बचते हैं और लंबे फॉर्म को पसंद करते हैं।

यह "केवल एक वापसी" की धारणा कहां से आई? क्या एक ऐतिहासिक कारण है कि इस सम्मेलन के बारे में क्यों आया?


2
यह कुछ हद तक गार्ड क्लॉज रिफैक्टिंग से जुड़ा है। stackoverflow.com/a/8493256/679340 गार्ड क्लॉज आपके तरीकों की शुरुआत में रिटर्न जोड़ देगा। और यह मेरी राय में कोड को बहुत क्लीनर बनाता है।
पायोत्र पेरक

3
यह संरचित प्रोग्रामिंग की धारणा से आया है। कुछ लोग यह तर्क दे सकते हैं कि सिर्फ एक रिटर्न होने से आप कोड को संशोधित करने के लिए आसानी से वापस लौटने से पहले या आसानी से डिबग कर सकते हैं।
मार्टिंकव्यूव

3
मुझे लगता है कि उदाहरण एक सरल पर्याप्त मामला है जहां मैं एक तरह से एक मजबूत राय या दूसरा नहीं होगा। सिंगल-एंट्री-सिंगल-एग्जिट आदर्श हमें 15 रिटर्न स्टेटमेंट और दो और शाखाओं जैसे पागल स्थितियों से दूर मार्गदर्शन करने के लिए अधिक है जो बिल्कुल भी वापस नहीं आते हैं!
मेंडोटा

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

3
आपको स्थिति को पूरी तरह से हटा देना चाहिए। जवाब 42 है।
16

जवाबों:


1119

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

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

      SUBROUTINE S(X, Y)
      R = SQRT(X*X + Y*Y)
C ALTERNATE ENTRY USED WHEN R IS ALREADY KNOWN
      ENTRY S2(R)
      ...
      RETURN
      END

C USAGE
      CALL S(3,4)
C ALTERNATE USAGE
      CALL S2(5)

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

C SUBROUTINE WITH ALTERNATE RETURN.  THE '*' IS A PLACE HOLDER FOR THE ERROR RETURN
      SUBROUTINE QSOLVE(A, B, C, X1, X2, *)
      DISCR = B*B - 4*A*C
C NO SOLUTIONS, RETURN TO ERROR HANDLING LOCATION
      IF DISCR .LT. 0 RETURN 1
      SD = SQRT(DISCR)
      DENOM = 2*A
      X1 = (-B + SD) / DENOM
      X2 = (-B - SD) / DENOM
      RETURN
      END

C USE OF ALTERNATE RETURN
      CALL QSOLVE(1, 0, 1, X1, X2, *99)
C SOLUTION FOUND
      ...
C QSOLVE RETURNS HERE IF NO SOLUTIONS
99    PRINT 'NO SOLUTIONS'

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


38
और स्पेगेटी कोड मत भूलना । यह सबरूटीन के लिए एक रिटर्न के बजाय एक GOTO का उपयोग करने से बाहर निकलने के लिए अज्ञात नहीं था, फ़ंक्शन कॉल मापदंडों को छोड़कर और स्टैक पर रिटर्न एड्रेस। एकल निकास को कम से कम फ़नल तक सभी कोड पथों के लिए एक RETURN कथन के रूप में प्रचारित किया गया था।
TMN

2
@ टीएमएन: शुरुआती दिनों में, अधिकांश मशीनों में हार्डवेयर स्टैक नहीं था। आम तौर पर समर्थन का समर्थन नहीं किया गया था। सबरूटीन तर्क और रिटर्न पता सबरूटीन कोड से सटे निश्चित स्थानों में संग्रहीत किए गए थे। रिटर्न सिर्फ एक अप्रत्यक्ष गोटो था।
केविन क्लाइन

5
@kevin: हाँ, लेकिन आपके अनुसार इसका मतलब यह भी नहीं है कि इसका आविष्कार किस रूप में किया गया था। (BTW, मुझे वास्तव में यकीन है कि फ्रेड ने पूछा "सिंगल एक्ज़िट" की वर्तमान व्याख्या के लिए प्राथमिकता क्या है।) इसके अलावा, सी के पास पहले constसे ही कई उपयोगकर्ता पैदा हुए थे, इसलिए अब और पूंजी स्थिरांक की कोई आवश्यकता नहीं है। यहां तक ​​कि सी। लेकिन जावा में उन सभी पुरानी पुरानी आदतों को संरक्षित किया गया था
sbi

3
तो क्या अपवाद एकल निकास की इस व्याख्या का उल्लंघन करते हैं? (या उनके अधिक आदिम चचेरे भाई setjmp/longjmp?)
मेसन व्हीलर

2
भले ही ऑप ने सिंगल रिटर्न की वर्तमान व्याख्या के बारे में पूछा, यह उत्तर सबसे ऐतिहासिक जड़ों वाला है। एक नियम के रूप में एक ही रिटर्न का उपयोग करने का कोई मतलब नहीं है , जब तक कि आप अपनी भाषा को वीबी (नहीं .NET) की अजीबता से मेल खाना चाहते हैं। बस गैर-शॉर्ट-सर्किट बूलियन तर्क का उपयोग करना याद रखें।
तेज

912

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

void f()
{
  resource res = acquire_resource();  // think malloc()
  if( f1(res) )
    return; // leaks res
  f2(res);
  release_resource(res);  // think free()
}

ऐसी भाषाओं में, आपके पास मूल रूप से तीन विकल्प हैं:

  • सफाई कोड दोहराएं।
    ओह। अतिरेक हमेशा बुरा होता है।

  • gotoसफाई कोड पर जाने के लिए a का उपयोग करें ।
    यह फ़ंक्शन में अंतिम कोड के लिए क्लीनअप कोड की आवश्यकता है। (और यही कारण है कि कुछ का तर्क है कि gotoइसकी जगह है। और यह वास्तव में है - सी में)

  • एक स्थानीय चर का परिचय और उस के माध्यम से नियंत्रण प्रवाह में हेरफेर।
    नुकसान (लगता है कि नियंत्रण प्रवाह वाक्य रचना के माध्यम से चालाकी से किया है break, return, if, while) ज्यादा नियंत्रण प्रवाह चर के राज्य के माध्यम से चालाकी से (क्योंकि वे चर कोई राज्य है जब आप कलन विधि को देखो) से पालन करने के लिए आसान है।

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

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


हालाँकि, जब कोई भाषा अपवादों को शामिल करती है, (लगभग) किसी भी फ़ंक्शन को समय से पहले (लगभग) किसी भी बिंदु से बाहर किया जा सकता है, इसलिए आपको वैसे भी समय से पहले वापसी के लिए प्रावधान करने की आवश्यकता है। (मुझे लगता finallyहै कि मुख्य रूप से इसके लिए जावा में प्रयोग किया जाता है और using(लागू करते समय IDisposable, finallyअन्यथा) C # में; C ++ के बजाय RAII को नियोजित करता है ।) एक बार जब आप ऐसा कर लेते हैं , तो आप एक प्रारंभिक returnबयान के कारण अपने आप को साफ करने में विफल नहीं हो सकते हैं , इसलिए शायद यह क्या है। SESE के पक्ष में सबसे मजबूत तर्क गायब हो गया है।

जो पठनीयता छोड़ देता है। बेशक, आधा दर्जन returnबयानों के साथ 200 एलओसी समारोह बेतरतीब ढंग से छिड़ गया, यह अच्छी प्रोग्रामिंग शैली नहीं है और पठनीय कोड के लिए नहीं है। लेकिन इस तरह के एक फ़ंक्शन को उन समयपूर्व रिटर्न के बिना समझना आसान नहीं होगा।

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


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

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


52
सही। जावा में, क्लीनअप कोड उन finallyखंडों में होता है जहाँ इसे आरंभिक returnएस या अपवादों की परवाह किए बिना निष्पादित किया जाता है।
dan04

15
जावा 7 में @ dan04 आपको finallyसमय की सबसे अधिक आवश्यकता नहीं है ।
आर। मार्टिनो फर्नांडीस

93
@ उत्तर: निश्चित रूप से आप इसे प्रदर्शित कर सकते हैं! वास्तव में, आप किसी भी विशेषता के साथ जटिल और जटिल कोड दिखा सकते हैं जो कोड को सरल और समझने में आसान बनाने के लिए भी दिखाया जा सकता है। हर चीज का दुरुपयोग हो सकता है। बिंदु कोड लिखना है, ताकि इसे समझना आसान हो , और जब इसमें SESE को खिड़की से बाहर फेंकना शामिल हो, तो ऐसा हो, और पुरानी आदतों को धिक्कारें जो विभिन्न भाषाओं पर लागू होती हैं। लेकिन मुझे लगता है कि अगर मुझे लगता है कि यह कोड को पढ़ने के लिए आसान बना देता है तो मैं चर द्वारा निष्पादन को नियंत्रित करने में संकोच नहीं करूंगा। यह सिर्फ इतना है कि मुझे याद नहीं है कि लगभग दो दशकों में ऐसा कोड देखा गया था।
sbi

21
@ कार्ल: वास्तव में, यह जावा जैसी जीसी भाषाओं की भारी कमी है कि वे आपको एक संसाधन को साफ करने से रोकते हैं, लेकिन अन्य सभी के साथ असफल हो जाते हैं। (C ++ RAII का उपयोग करते हुए सभी संसाधनों के लिए इस समस्या को हल करता है ।) लेकिन मैं केवल मेमोरी की बात नहीं कर रहा था (मैंने केवल एक उदाहरण के रूप में एक टिप्पणी में malloc()और free()टिप्पणी की), मैं सामान्य रूप से संसाधनों के बारे में बात कर रहा था। मैं भी आसन्न नहीं था जीसी इन समस्याओं को हल करेगा। (मैंने C ++ का उल्लेख किया है, जिसमें जीसी बॉक्स से बाहर नहीं है।) जो मैं समझता हूं, जावा finallyमें इस समस्या को हल करने के लिए उपयोग किया जाता है।
sbi

10
@ एसएसबी: फ़ंक्शन के लिए अधिक महत्वपूर्ण है (प्रक्रिया, विधि, आदि) पृष्ठ स्पष्ट रूप से परिभाषित अनुबंध होने के लिए फ़ंक्शन से अधिक लंबा नहीं है; अगर यह कुछ स्पष्ट नहीं कर रहा है क्योंकि यह एक मनमाना लंबाई बाधा को संतुष्ट करने के लिए कटा हुआ है, तो यह बुरा है। प्रोग्रामिंग अलग-अलग खेलने के बारे में है, कभी-कभी परस्पर विरोधी ताकतों के खिलाफ।
डोनल फैलो

81

एक तरफ, एकल रिटर्न स्टेटमेंट लॉगिंग को आसान बनाते हैं, साथ ही डिबगिंग के रूपों को भी लॉगिंग पर भरोसा करते हैं। मुझे बार-बार याद है कि मुझे एक ही बिंदु पर रिटर्न वैल्यू का प्रिंट निकालने के लिए फ़ंक्शन को सिंगल रिटर्न में कम करना था।

  int function() {
     if (bidi) { print("return 1"); return 1; }
     for (int i = 0; i < n; i++) {
       if (vidi) { print("return 2"); return 2;}
     }
     print("return 3");
     return 3;
  }

दूसरी ओर, आप इसे function()कॉल _function()और उस परिणाम को लॉग करने में इसे रिफैक्ट कर सकते हैं ।


31
मैं यह भी जोड़ूंगा कि यह डिबगिंग को आसान बनाता है क्योंकि आपको केवल फ़ंक्शन से सभी निकासों को पकड़ने के लिए एक ब्रेकपॉइंट सेट करने की आवश्यकता है। मेरा मानना ​​है कि कुछ आईडीई आपको एक ही काम करने के लिए फ़ंक्शन के करीबी ब्रेस पर ब्रेकपॉइंट लगाते हैं। (* जब तक आप बाहर न निकलें)
Skizz

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

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

11
कुछ डिबगर (MSVS) में आप अंतिम समापन ब्रेस पर ब्रेकपॉइंट लगा सकते हैं
Abyx

6
मुद्रण! = डिबगिंग। यह बिल्कुल तर्क नहीं है।
पियोट्र पर्क

53

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

"GOTO स्टेटमेंट कंसीडरेड हार्मफुल" को आज भी पढ़ना आवश्यक है। "संरचित प्रोग्रामिंग" दिनांकित है, लेकिन अभी भी बहुत, बहुत पुरस्कृत है, और किसी भी डेवलपर की "मस्ट रीड" सूची में सबसे ऊपर होना चाहिए, जैसे कि स्टीव मैकोनेल से कुछ भी ऊपर। (डाहल का खंड सिमूला 67 में कक्षाओं की मूल बातें बताता है, जो सी ++ में कक्षाओं के लिए तकनीकी आधार हैं और सभी वस्तु-उन्मुख प्रोग्रामिंग हैं।)


6
लेख को C से पहले उन दिनों में लिखा गया था जब GOTO का भारी उपयोग किया गया था। वे दुश्मन नहीं हैं, लेकिन यह जवाब निश्चित रूप से सही है। एक वापसी बयान एक समारोह के अंत में नहीं है कि प्रभावी रूप से एक गोटो है।
15:60 बजे user606723

31
यह लेख उन दिनों में भी लिखा गया था जब gotoसचमुच कहीं भी जा सकते थे , जैसे किसी फ़ंक्शन में कुछ यादृच्छिक बिंदु पर अधिकार, प्रक्रियाओं, कार्यों, कॉल स्टैक, आदि की किसी भी धारणा को दरकिनार करते हुए। कोई भी समझदार भाषा अनुमति नहीं देती है कि इन दिनों एक सीधे के साथ goto। C का setjmp/ longjmpकेवल अर्ध-असाधारण मामला है, जिसके बारे में मुझे पता है, और यहां तक ​​कि दोनों सिरों से सहयोग की आवश्यकता है। (अर्ध-विडंबना है कि मैंने वहां "असाधारण" शब्द का इस्तेमाल किया, हालांकि, यह देखते हुए कि अपवाद लगभग एक ही काम करते हैं ...) मूल रूप से, लेख एक अभ्यास को हतोत्साहित करता है जो लंबे समय से मृत है।
cHao

5
"गोटो स्टेटमेंट को हानिकारक माना जाता है" के अंतिम पैराग्राफ से: [2] में गुइसेप्पे जैकोपिनी ने कहा है कि यह कथन के लिए (तार्किक) अतिरेक साबित हुआ है। एक मनमाना प्रवाह आरेख का अनुवाद करने के लिए व्यायाम कमोबेश एक छलांग में होता है। कम एक, हालांकि, अनुशंसित नहीं है । तब परिणामी प्रवाह आरेख मूल एक की तुलना में अधिक पारदर्शी होने की उम्मीद नहीं की जा सकती है। "
hugomg

10
प्रश्न से इसका क्या लेना-देना है? हां, दिज्क्स्ट्रा के काम ने आखिरकार SESE भाषाओं को जन्म दिया, और इसलिए क्या? तो बैबेज का काम किया। और शायद आपको पेपर को फिर से पढ़ना चाहिए अगर आपको लगता है कि यह किसी फ़ंक्शन में एकाधिक निकास बिंदु होने के बारे में कुछ भी कहता है । क्योंकि यह नहीं है।
jalf

10
@ जॉन, आप वास्तव में इसका जवाब दिए बिना सवाल का जवाब देने की कोशिश कर रहे हैं। यह एक अच्छी पठन सूची है, लेकिन आपने अपने दावे को सही ठहराने के लिए न तो कुछ उद्धृत किया है और न ही कुछ विरोधाभास किया है कि इस निबंध और पुस्तक में पूछने वाले की चिंता के बारे में कुछ भी कहना है। वास्तव में, टिप्पणियों के बाहर आपने जो भी प्रश्न के बारे में पर्याप्त कुछ नहीं कहा है । इस उत्तर का विस्तार करने पर विचार करें।
Shog9

35

फाउलर को लिंक करना हमेशा आसान होता है।

SESE के खिलाफ जाने वाले मुख्य उदाहरणों में से एक गार्ड क्लॉस हैं:

गार्ड क्लाज के साथ नेस्टेड कंडिशनल बदलें

सभी विशेष मामलों के लिए गार्ड क्लॉज का उपयोग करें

double getPayAmount() {
    double result;
    if (_isDead) result = deadAmount();
    else {
        if (_isSeparated) result = separatedAmount();
        else {
            if (_isRetired) result = retiredAmount();
            else result = normalPayAmount();
        };
    }
return result;
};  

                                                                                                         http://www.refactoring.com/catalog/arrow.gif

double getPayAmount() {
    if (_isDead) return deadAmount();
    if (_isSeparated) return separatedAmount();
    if (_isRetired) return retiredAmount();
    return normalPayAmount();
};  

अधिक जानकारी के लिए देखें रिफैक्टरिंग के पेज 250 ...


11
एक और बुरा उदाहरण: यह बस के रूप में आसानी से तय किया जा सकता है-ifs।
जैक

1
आपका उदाहरण उचित नहीं है, इस बारे में कैसे: डबल getPayAmount () {डबल रिट = normalPayAmount (); if (_isDead) ret = deadAmount (); if (_isSeparated) ret = से अलग होना (); if (_isRetired) ret = retiredAmount (); वापसी; };
चारबेल

6
@Charbel यही बात नहीं है। यदि _isSeparatedऔर _isRetiredदोनों सच हो सकता है (और क्यों यह संभव नहीं हो सकता है?) आप गलत राशि वापस जाएँ।
hvd

2
@ कोंचोग " नेस्टेड सशर्त गार्ड क्लॉस की तुलना में बेहतर निष्पादन समय प्रदान करेगा " यह प्रमुख रूप से एक प्रशस्ति पत्र की जरूरत है। मुझे अपने संदेह हैं कि यह मज़बूती से सच है। इस मामले में, उदाहरण के लिए, उत्पन्न कोड के संदर्भ में तार्किक शॉर्ट-सर्कुलेटिंग से किसी भी तरह के शुरुआती रिटर्न कैसे अलग हैं? यहां तक ​​कि अगर यह मायने रखता है, मैं एक ऐसे मामले की कल्पना नहीं कर सकता जहां अंतर एक infinitesimal sliver से अधिक होगा। इसलिए आप कोड को कम पठनीय बनाकर समय से पहले अनुकूलन कर रहे हैं, बस आपको जो कुछ भी लगता है उसके बारे में कुछ अप्रमाणिक सैद्धांतिक बिंदु को संतुष्ट करने के लिए थोड़ा और अधिक कोड की ओर जाता है। हम यहां ऐसा नहीं करते हैं
अंडरस्कोर_ड

1
@underscore_d, आप सही कह रहे हैं। यह संकलक पर बहुत कुछ निर्भर करता है, लेकिन यह अधिक स्थान ले सकता है .. दो छद्म-विधानसभाओं को देखें और यह देखना आसान है कि गार्ड क्लॉस उच्च स्तर की भाषाओं से क्यों आते हैं। "ए" परीक्षण (1); ब्रांच_फेल एंड; परीक्षण (2); ब्रांच_फेल एंड; परीक्षण (3); ब्रांच_फेल एंड; {CODE} अंत: वापसी; "बी" परीक्षण (1); Branch_good next1; वापसी; अगला 1: परीक्षण (2); Branch_good अगला 2; वापसी; अगला 2: परीक्षण (3); Branch_good अगले 3; वापसी; अगला 3: {CODE} वापसी;
कोंचग

11

मैंने कुछ समय पहले इस विषय पर एक ब्लॉग पोस्ट लिखा था।

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

यह सवाल स्टाकेवरफ्लो पर भी पूछा गया है


अरे, मैं अब उस लिंक तक नहीं पहुँच सकता। क्या आपके पास एक ऐसा संस्करण है जो कहीं न कहीं अभी भी सुलभ है?
निक हार्टले

नमस्ते, क्यूपीटी, अच्छा स्थान। मैं ब्लॉग पोस्ट को वापस लाया हूं और ऊपर दिए गए URL को अपडेट किया है। इसे अब लिंक करना चाहिए!
एंथनी

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

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

मेहरदाद, यदि इसके समर्थन में कोई औपचारिक अध्ययन है, तो इसे दिखाएं। बस इतना ही। के खिलाफ सबूत पर जोर देना सबूत के बोझ को हिला रहा है।
एंथनी

7

एक वापसी refactoring आसान बनाता है। एक लूप के आंतरिक शरीर के लिए "अर्क विधि" करने की कोशिश करें जिसमें एक वापसी, ब्रेक या जारी है। यह विफल हो जाएगा क्योंकि आपने अपना नियंत्रण प्रवाह तोड़ दिया है।

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

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


यही बात चरों पर लागू होती है। जो प्रारंभिक रिटर्न की तरह नियंत्रण-प्रवाह-निर्माण का उपयोग करने का विकल्प हैं।
डेडुप्लिकेटर

वेरिएबल्स ज्यादातर आपको अपने कोड को टुकड़ों में तोड़ने के लिए बाधा नहीं डालेंगे कि मौजूदा नियंत्रण प्रवाह संरक्षित है। "एक्स्ट्रेक्ट मेथड" आज़माएँ। आईडीई केवल नियंत्रण प्रवाह प्रीरेविंज रिफ्लेक्टरिंग करने में सक्षम हैं क्योंकि वे आपके द्वारा लिखे गए शब्दार्थों को प्राप्त करने में सक्षम नहीं हैं।
oopexpert

5

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

हालाँकि, मैं इस प्रकार के GOTO के हानिकारक होने पर विचार नहीं करता और अपने कोड में एक वास्तविक GOTO का उपयोग करने में संकोच नहीं करूँगा अगर मुझे इसका कोई अच्छा कारण मिल जाए।

मेरा सामान्य नियम यह है कि GOTO केवल प्रवाह नियंत्रण के लिए है। उन्हें कभी भी किसी भी लूपिंग के लिए उपयोग नहीं किया जाना चाहिए, और आपको कभी भी 'ऊपर की ओर' या 'पीछे की ओर' नहीं जाना चाहिए। (जो है कि कैसे टूटता है / रिटर्न काम करता है)

जैसा कि अन्य लोगों ने उल्लेख किया है, निम्नलिखित को अवश्य पढ़ें GOTO स्टेटमेंट कंसीडरेड हार्मफुल
हालांकि, ध्यान रखें कि यह 1970 में लिखा गया था जब GOTO का अत्यधिक उपयोग किया गया था। प्रत्येक GOTO हानिकारक नहीं है और मैं उनके उपयोग को तब तक हतोत्साहित नहीं करूंगा जब तक आप सामान्य निर्माणों के बजाय उनका उपयोग नहीं करते हैं, लेकिन इस विषम स्थिति में कि सामान्य निर्माणों का उपयोग करना अत्यधिक असुविधाजनक होगा।

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


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

टूक, लेकिन यह मेरी बात अलग नहीं है ... यह सिर्फ मेरे स्पष्टीकरण को थोड़ा गलत बनाता है। ओह अच्छा।
user606723

GOTO हमेशा ठीक होना चाहिए जब तक (1) लक्ष्य एक ही विधि या फ़ंक्शन में है और (2) दिशा कोड में आगे है (कुछ कोड छोड़ें) और (3) लक्ष्य कुछ अन्य नेस्टेड संरचना के अंदर नहीं है (जैसे गोटो अगर-केस के बीच से और-केस के बीच में)। यदि आप इन नियमों का पालन करते हैं, तो GOTO के सभी दुरुपयोगों में नेत्रहीन और तार्किक रूप से एक मजबूत कोड गंध है।
मिकको रैंटलैनेन

3

साइक्लोमेटिक कम्पलेक्सिटी

मैंने देखा है कि सोनारक्यूब ने साइक्लोमैटिक जटिलता निर्धारित करने के लिए कई रिटर्न स्टेटमेंट का उपयोग किया है। तो अधिक वापसी बयान, उच्च चक्रवाती जटिलता

वापसी प्रकार बदलें

एकाधिक रिटर्न का मतलब है कि जब हम अपने रिटर्न प्रकार को बदलने का फैसला करते हैं तो हमें फ़ंक्शन में कई स्थानों पर बदलने की आवश्यकता होती है।

एकाधिक बाहर निकलें

डीबग करना कठिन है क्योंकि लौटे मूल्य के कारण समझने के लिए तर्कपूर्ण बयानों के संयोजन के साथ तर्क का सावधानीपूर्वक अध्ययन करने की आवश्यकता है।

रिफैक्टर्ड सॉल्यूशन

मल्टीपल रिटर्न स्टेटमेंट्स का हल उन्हें पॉलीमॉर्फिज्म के साथ बदलना है ताकि आवश्यक कार्यान्वयन ऑब्जेक्ट को हल करने के बाद एक ही रिटर्न हो।


3
एक से अधिक रिटर्न से कई स्थानों पर रिटर्न वैल्यू सेट करने से साइक्लोमैटिक जटिलता समाप्त नहीं होती है, यह केवल निकास स्थान को एकीकृत करती है। सभी समस्याएं जो दिए गए संदर्भ में चक्रीय जटिलता को इंगित कर सकती हैं, बनी हुई हैं। "यह डीबग करना कठिन है क्योंकि लॉजिक वैल्यू के कारण तर्क को ध्यान से समझने के लिए तर्क का सावधानीपूर्वक अध्ययन करने की आवश्यकता है" फिर से, रिटर्न को एकजुट करके तर्क नहीं बदलता है। यदि आपको यह समझने के लिए कोड का सावधानीपूर्वक अध्ययन करना है कि यह कैसे काम करता है, तो इसे फिर से भरना, पूर्ण विराम देना होगा।
विल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.