किसी फ़ंक्शन के पास केवल एक निकास बिंदु क्यों होना चाहिए? [बन्द है]


97

मैंने हमेशा एक ही एग्जिट-पॉइंट फंक्शन के बारे में सुना है क्योंकि यह एक बुरा तरीका है क्योंकि आप पठनीयता और दक्षता खो देते हैं। मैंने कभी नहीं सुना है कि कोई भी दूसरे पक्ष से बहस करे।

मैंने सोचा कि यह सीएस के साथ कुछ करना था, लेकिन यह सवाल cstheory stackexchange पर शूट किया गया था।



6
इसका उत्तर यह है कि ऐसा कोई उत्तर नहीं है जो हमेशा सही हो। मुझे अक्सर w / एकाधिक निकास कोड को आसान लगता है। मैंने भी पाया है (ऊपर दिए गए कोड को अपडेट करते समय) कोड को संशोधित / विस्तारित करना उन्हीं एकाधिक निकासों के कारण अधिक कठिन था। इन केस-बाय-केस के फैसले करना हमारा काम है। जब एक निर्णय में हमेशा "सर्वश्रेष्ठ" उत्तर होता है, तो हमारे लिए कोई आवश्यकता नहीं होती है।
जेएस।

1
@finnw फासीवादी तौर-तरीकों ने पिछले दो प्रश्नों को हटा दिया है, यह सुनिश्चित करने के लिए कि उन्हें फिर से, और फिर से उत्तर देना होगा, और फिर
Maarten Bodewes

प्रश्न में "तर्क" शब्द के बावजूद, मुझे नहीं लगता कि यह एक राय आधारित प्रश्न है। यह अच्छे डिजाइन के लिए काफी प्रासंगिक है, आदि मैं इसे बंद करने का कोई कारण नहीं देखता, लेकिन w / e।
नागार्जुन

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

जवाबों:


108

विचार के विभिन्न स्कूल हैं, और यह काफी हद तक व्यक्तिगत पसंद में आता है।

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

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

एक तीसरा यह है कि आप कृपया कहीं भी बाहर निकल सकते हैं। पुराने दिनों में यह अधिक भ्रामक हुआ करता था, लेकिन अब जब हमारे पास सिंटेक्स-कलरिंग एडिटर और कंपाइलर हैं, जो अगम्य कोड का पता लगाते हैं, तो इससे निपटना बहुत आसान है।

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


1
बयानों के माध्यम से singe exitप्रतिमान में गहरी घोंसले का शिकार किया जा सकता है go to। इसके अलावा, किसी को फ़ंक्शन के स्थानीय Errorलेबल के तहत कुछ पोस्टप्रोसेसिंग करने का अवसर मिलता है , जो कई returnएस के साथ असंभव है ।
Ant_222

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

उद्देश्य मानदंडों के आधार पर एक इष्टतम दृष्टिकोण है लेकिन हम इस बात से सहमत हो सकते हैं कि विचार (सही और गलत) के स्कूल हैं और यह व्यक्तिगत प्राथमिकता (एक सही दृष्टिकोण के लिए एक वरीयता या खिलाफ) के लिए नीचे आता है।
रिक ओ'शिए

39

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

  if (तर्क) // अगर गैर-शून्य की जाँच करें
    ERR_NULL_ARGUMENT पर लौटें;
  ... प्रक्रिया गैर-अशक्त तर्क
  अगर (ठीक है)
    वापसी 0;
  अन्य
    वापसी ERR_NOT_OK;

से अधिक स्पष्ट:

  int return_value;
  if (तर्क) // गैर-अशक्त
  {
    .. प्रक्रिया गैर-अशक्त तर्क
    .. उचित परिणाम सेट करें
  }
  अन्य
    परिणाम = ERR_NULL_ARGUMENT;
  वापसी परिणाम;

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


आपका पहला उदाहरण, okवैरिएबल का प्रबंधन , मेरे लिए एकल-वापसी दृष्टिकोण के रूप में दिखता है। इसके अलावा, अगर-ब्लॉक को फिर से लिखा जा सकता है:return ok ? 0 : ERR_NOT_OK;
मेलेबियस

2
पहला उदाहरण returnसभी कोड से पहले एक शुरुआत में है जो सब कुछ करता है। ?:ऑपरेटर का उपयोग करने के लिए , अलग-अलग लाइनों पर इसे लिखने से कई आईडीई पर डिबग ब्रेकपॉइंट को संलग्न करने के लिए आसान नहीं है, ठीक नहीं है। BTW, "सिंगल एग्जिट पॉइंट" की असली कुंजी यह समझने में निहित है कि सामान्य फ़ंक्शन के लिए प्रत्येक विशेष कॉल के लिए क्या मायने रखता है , कॉल के तुरंत बाद एग्ज़िट पॉइंट बिंदु है । प्रोग्रामर आजकल ले लेते हैं कि दी गई, लेकिन चीजें हमेशा इस प्रकार नहीं थीं। कुछ दुर्लभ मामलों में कोड को स्टैक स्पेस के बिना प्राप्त करना पड़ सकता है, जिससे कार्य हो सकता है ...
सुपरकैट

... जो सशर्त या गणना गोटो के माध्यम से बाहर निकलते हैं। आम तौर पर असेंबली लैंग्वेज के अलावा किसी और चीज में प्रोग्राम किए जाने वाले पर्याप्त संसाधनों के साथ स्टैक को सपोर्ट किया जा सकेगा, लेकिन मैंने असेंबली कोड लिखा है जिसे कुछ बहुत ही तंग बाधाओं (एक मामले में RAM के Zero बाइट्स के नीचे) में संचालित करना था, और कई एग्जिट पॉइंट्स होने से ऐसे मामलों में मदद मिल सकती है।
सुपरकैट

1
सामाजिक रूप से स्पष्ट उदाहरण बहुत कम स्पष्ट और पढ़ने में कठिन है। एक निकास बिंदु हमेशा पढ़ने में आसान, बनाए रखने में आसान, डिबग करने में आसान होता है।
गुइडोग

8
@GuidoG: छोड़े गए वर्गों में जो दिखता है, उसके आधार पर या तो पैटर्न अधिक पठनीय हो सकता है। "रिटर्न x" का उपयोग करना यह स्पष्ट करता है कि यदि कथन तक पहुँच गया है, तो वापसी मूल्य x होगा। "परिणाम = x" का उपयोग करना पत्ते इस संभावना को खोलते हैं कि कुछ और वापस आने से पहले परिणाम बदल सकता है। यह उपयोगी हो सकता है अगर यह वास्तव में परिणाम को बदलने के लिए आवश्यक हो जाएगा, लेकिन कोड की जांच करने वाले प्रोग्रामर को यह देखने के लिए निरीक्षण करना होगा कि उत्तर "यह नहीं हो सकता है" तो भी परिणाम कैसे बदल सकता है।
सुपरकैट

15

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


यह वास्तव में RAII के साथ एक मुद्दा नहीं है
BigSandwich

14

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

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

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

- 2 सेंट

कृपया अधिक जानकारी के लिए इस दस्तावेज़ को देखें: NISTIR 5459


8
multiple returns in a function requires a much deeper analysisकेवल अगर फ़ंक्शन पहले से ही विशाल है (> 1 स्क्रीन), अन्यथा यह विश्लेषण को आसान बनाता है
dss539

2
कई रिटर्न विश्लेषण को आसान कभी नहीं बनाता है, बस विपरीत
GuidoG

1
लिंक मृत है (404)।
फूसी

1
@fusi - इसे आर्काइव.ऑर्ग पर पाया गया और लिंक को यहां अपडेट किया गया
sscheider

4

मेरे विचार में, केवल एक बिंदु पर एक फ़ंक्शन (या अन्य नियंत्रण संरचना) से बाहर निकलने की सलाह अक्सर ओवरसोल्ड होती है। आमतौर पर केवल एक बिंदु पर बाहर निकलने के लिए दो कारण दिए गए हैं:

  1. एकल-निकास कोड को पढ़ना और डीबग करना आसान माना जाता है। (मैं मानता हूं कि मैं इस कारण से ज्यादा नहीं सोचता, लेकिन यह दिया गया है। क्या पढ़ना और डिबग करना काफी आसान है, एकल प्रविष्टि कोड है।)
  2. सिंगल-एग्जिट कोड लिंक और अधिक सफाई से लौटता है।

दूसरा कारण सूक्ष्म है और इसमें कुछ योग्यता है, खासकर यदि फ़ंक्शन एक बड़ी डेटा संरचना लौटाता है। हालाँकि, मैं इसके बारे में बहुत अधिक चिंता नहीं करूंगा, सिवाय ...

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

सौभाग्य।


4

मैं सिंगल-एक्जिट स्टाइल का हिमायती हुआ करता था। मेरा तर्क ज्यादातर दर्द से आया ...

एकल-निकास डीबग करना आसान है।

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

यह विशेष रूप से सच हो गया जब आपको राज्य की जांच करने के लिए असाइनमेंट्स को बीच में लाने की जरूरत थी (आधुनिक डिबगर्स में घड़ी के भावों के साथ)। समस्या को छिपाने या निष्पादन को पूरी तरह से तोड़ने के तरीकों में नियंत्रण प्रवाह को बदलना भी बहुत आसान था।

एकल-निकास विधियों को डीबगर में ले जाना आसान था, और तर्क को तोड़े बिना अलग करना आसान था।


0

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

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

सबसे अच्छी बात यह है कि आप जाते ही सीख जाएंगे। यदि आप किसी चीज़ के लिए कोड लिख रहे हैं, तो दूसरे लोगों का कोड खोजने की कोशिश करें और देखें कि वे इसे कैसे लागू करते हैं। तय करें कि आपको कौन सा बिट पसंद है और कौन सा बिट्स आपको नहीं।


-5

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

मैं रॉबर्ट सी। मार्टिन की पुस्तक क्लीन कोड में कार्यों के बारे में अध्याय पढ़ने की सलाह दूंगा।

अनिवार्य रूप से, आपको कोड की 4 पंक्तियों या उससे कम के साथ फ़ंक्शन लिखने का प्रयास करना चाहिए।

माइक लॉन्ग ब्लॉग के कुछ नोट्स :

  • कार्यों का पहला नियम: उन्हें छोटा होना चाहिए
  • कार्यों का दूसरा नियम: उन्हें इससे छोटा होना चाहिए
  • अगर स्टेटमेंट्स के भीतर ब्लॉक्स, लूप्स के लिए स्टेटमेंट आदि एक लाइन लंबे होने चाहिए
  • ... और कोड की वह पंक्ति आमतौर पर एक फ़ंक्शन कॉल होगी
  • इंडेंटेशन के एक या दो स्तर से अधिक नहीं होना चाहिए
  • कार्यों को एक काम करना चाहिए
  • समारोह कथन सभी अमूर्तता के समान स्तर पर होने चाहिए
  • एक फ़ंक्शन में 3 से अधिक तर्क नहीं होने चाहिए
  • आउटपुट तर्क एक कोड गंध हैं
  • एक समारोह में बूलियन ध्वज पारित करना वास्तव में भयानक है। आप फंक्शन में दो टाइमिंग कर रहे हैं।
  • दुष्प्रभाव झूठ हैं।

29
4 लाइनों? आप क्या कोड करते हैं जो आपको इस तरह की सरलता प्रदान करता है? मुझे वास्तव में संदेह है कि लिनक्स कर्नेल या उदाहरण के लिए git ऐसा करता है।
shinzou

7
"एक समारोह में बूलियन ध्वज को पारित करना वास्तव में भयानक है। आप फ़ंक्शन में दो-कार्य कर रहे हैं।" परिभाषा से? नहीं ... वह बूलियन संभवतः आपकी चार लाइनों में से एक को प्रभावित कर सकता है। इसके अलावा जब मैं फ़ंक्शन आकार को छोटा रखने से सहमत हूं, तो चार थोड़ा प्रतिबंधात्मक है। इसे बहुत ढीली गाइडलाइन के रूप में लिया जाना चाहिए।
जेसी

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

10
एसओ पर दुर्लभ उत्तरों में से एक यह है कि काश मैं कई बार डाउनवोट होता।
स्टीवन रैंड

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