कौन सा और क्यों, क्या आप अपवाद या रिटर्न कोड पसंद करते हैं?


92

मेरा सवाल यह है कि ज्यादातर डेवलपर्स त्रुटि से निपटने, अपवाद या त्रुटि रिटर्न कोड के लिए क्या पसंद करते हैं। कृपया भाषा (या भाषा परिवार) विशिष्ट हो और आप एक दूसरे को पसंद क्यों करते हैं।

मैं यह जिज्ञासा से बाहर पूछ रहा हूं। व्यक्तिगत रूप से मैं त्रुटि रिटर्न कोड पसंद करता हूं क्योंकि वे कम विस्फोटक होते हैं और उपयोगकर्ता कोड को अपवाद प्रदर्शन दंड का भुगतान करने के लिए मजबूर नहीं करते हैं यदि वे नहीं चाहते हैं।

अद्यतन: सभी उत्तर के लिए धन्यवाद! मुझे यह कहना होगा कि यद्यपि मैं अपवादों के साथ कोड प्रवाह की अप्रत्याशितता को नापसंद करता हूं। रिटर्न कोड (और उनके बड़े भाई हैंडल) के बारे में जवाब कोड में बहुत सारे शोर जोड़ते हैं।


1
सॉफ्टवेयर की दुनिया से एक चिकन या अंडे की समस्या ... सदा के लिए बहस का मुद्दा। :)
गिश्

इसके बारे में क्षमा करें, लेकिन उम्मीद है कि विभिन्न प्रकार की राय लोगों को (खुद शामिल) को उचित रूप से चुनने में मदद करेगी।
रॉबर्ट गोल्ड

जवाबों:


107

कुछ भाषाओं के लिए (यानी C ++) रिसोर्स लीक एक कारण नहीं होना चाहिए

C ++ RAII पर आधारित है।

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

रिटर्न कोड अधिक क्रिया हैं

वे क्रियात्मक हैं, और कुछ इस तरह विकसित होते हैं:

if(doSomething())
{
   if(doSomethingElse())
   {
      if(doSomethingElseAgain())
      {
          // etc.
      }
      else
      {
         // react to failure of doSomethingElseAgain
      }
   }
   else
   {
      // react to failure of doSomethingElse
   }
}
else
{
   // react to failure of doSomething
}

अंत में, आप कोड पहचान किए गए निर्देशों का एक संग्रह है (मैंने उत्पादन कोड में इस तरह का कोड देखा था)।

इस कोड का अच्छी तरह से अनुवाद किया जा सकता है:

try
{
   doSomething() ;
   doSomethingElse() ;
   doSomethingElseAgain() ;
}
catch(const SomethingException & e)
{
   // react to failure of doSomething
}
catch(const SomethingElseException & e)
{
   // react to failure of doSomethingElse
}
catch(const SomethingElseAgainException & e)
{
   // react to failure of doSomethingElseAgain
}

जो सफाई से कोड और एरर प्रोसेसिंग को अलग करता है, जो एक अच्छी बात हो सकती है।

रिटर्न कोड अधिक भंगुर होते हैं

यदि एक संकलक से कुछ अस्पष्ट चेतावनी नहीं मिलती है ("phjr" टिप्पणी देखें), तो उन्हें आसानी से अनदेखा किया जा सकता है।

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

त्रुटि को नजरअंदाज नहीं किया जाएगा। कभी-कभी, आप चाहते हैं कि यह विस्फोट न हो, हालांकि ... इसलिए आपको सावधानी से चुना जाना चाहिए।

रिटर्न कोड का कभी-कभी अनुवाद किया जाना चाहिए

मान लें कि हमारे पास निम्नलिखित कार्य हैं:

  • doSomething, जो NOT_FOUND_ERROR नामक int लौटा सकता है
  • doSomethingElse, जो एक बूल को "गलत" (असफल होने पर) लौटा सकता है
  • doSomethingElseAgain, जो एक त्रुटि ऑब्जेक्ट (__LINE__, __FILE__ और आधा स्टैक चर के साथ) वापस कर सकता है।
  • doTryToDoSomethingWithAllThisMess जो, अच्छी तरह से ... उपरोक्त कार्यों का उपयोग करें, और प्रकार का एक त्रुटि कोड लौटाएं ...

DoTryToDoSomethingWithAllThisMess की वापसी का प्रकार क्या है यदि इसके किसी भी कार्य में विफल रहता है?

रिटर्न कोड एक सार्वभौमिक समाधान नहीं हैं

ऑपरेटर एक त्रुटि कोड वापस नहीं कर सकते। C ++ कंस्ट्रक्टर भी नहीं कर सकते हैं।

रिटर्न कोड का मतलब है कि आप श्रृंखला अभिव्यक्ति नहीं कर सकते

उपरोक्त बिंदु का कोरोलरी। अगर मुझे लिखना है तो क्या होगा:

CMyType o = add(a, multiply(b, c)) ;

मैं नहीं कर सकता, क्योंकि वापसी मूल्य पहले से ही उपयोग किया जाता है (और कभी-कभी, इसे बदला नहीं जा सकता है)। तो रिटर्न वैल्यू पहला पैरामीटर बन जाता है, जिसे संदर्भ के रूप में भेजा जाता है ... या नहीं।

अपवाद टाइप किए गए हैं

आप प्रत्येक प्रकार के अपवाद के लिए अलग-अलग कक्षाएं भेज सकते हैं। स्रोतों के अपवाद (अर्थात स्मृति से बाहर) प्रकाश होना चाहिए, लेकिन कुछ और जितना आवश्यक हो उतना भारी हो सकता है (मुझे जावा एक्ससेप्शन मुझे पूरी तरह से देना पसंद है)।

प्रत्येक कैच को तब स्पेशलाइज किया जा सकता है।

फिर से फेंकने के बिना कभी भी पकड़ (...) का उपयोग न करें

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

अपवाद हैं ... NUKE

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

बेशक, सी ++ में, कभी भी एक अपवाद को एक विध्वंसक से बाहर निकलने न दें।

अपवाद हैं ... तुल्यकालिक

अपने धागे को उसके घुटनों पर लाने से पहले, या अपने विंडोज संदेश लूप के अंदर प्रचार करने से पहले उन्हें पकड़ना सुनिश्चित करें।

समाधान उन्हें मिश्रण हो सकता है?

इसलिए मुझे लगता है कि समाधान को फेंकना है जब कुछ नहीं होना चाहिए । और जब कुछ हो सकता है, तो उपयोगकर्ता को उस पर प्रतिक्रिया करने के लिए सक्षम करने के लिए एक रिटर्न कोड या एक पैरामीटर का उपयोग करें।

तो, एकमात्र सवाल "ऐसा क्या है जो नहीं होना चाहिए?"

यह आपके फ़ंक्शन के अनुबंध पर निर्भर करता है। यदि फ़ंक्शन पॉइंटर को स्वीकार करता है, लेकिन निर्दिष्ट करता है कि पॉइंटर नॉन-NULL होना चाहिए, तो उपयोगकर्ता द्वारा NULL पॉइंटर (प्रश्न C C + में होने पर, जब फ़ंक्शन लेखक ने संदर्भों का उपयोग नहीं किया, तो अपवाद को फेंकना ठीक है। संकेत के, लेकिन ...)

एक और समाधान त्रुटि दिखाने के लिए होगा

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

मेरी नौकरी में, हम एक तरह के "Assert" का उपयोग करते हैं। यह कॉन्फ़िगरेशन फ़ाइल के मूल्यों पर निर्भर करता है, कोई बात नहीं डिबग / रिलीज संकलन विकल्प:

  • त्रुटि लॉग करें
  • "अरे, आपको कोई समस्या है" के साथ एक संदेश बॉक्स खोलें
  • "अरे, आपको कोई समस्या है, क्या आप डीबग करना चाहते हैं" के साथ एक संदेश बॉक्स खोलें

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

विरासत कोड को जोड़ना आसान है। उदाहरण के लिए:

void doSomething(CMyObject * p, int iRandomData)
{
   // etc.
}

एक समान कोड की ओर जाता है:

void doSomething(CMyObject * p, int iRandomData)
{
   if(iRandomData < 32)
   {
      MY_RAISE_ERROR("Hey, iRandomData " << iRandomData << " is lesser than 32. Aborting processing") ;
      return ;
   }

   if(p == NULL)
   {
      MY_RAISE_ERROR("Hey, p is NULL !\niRandomData is equal to " << iRandomData << ". Will throw.") ;
      throw std::some_exception() ;
   }

   if(! p.is Ok())
   {
      MY_RAISE_ERROR("Hey, p is NOT Ok!\np is equal to " << p->toString() << ". Will try to continue anyway") ;
   }

   // etc.
}

(मेरे पास समान मैक्रोज़ हैं जो केवल डीबग पर सक्रिय हैं)।

ध्यान दें कि उत्पादन पर, कॉन्फ़िगरेशन फ़ाइल मौजूद नहीं है, इसलिए क्लाइंट इस मैक्रो का परिणाम कभी नहीं देखता है ... लेकिन जरूरत पड़ने पर इसे सक्रिय करना आसान है।

निष्कर्ष

जब आप रिटर्न कोड का उपयोग करके कोड बनाते हैं, तो आप अपने आप को असफलता के लिए तैयार कर रहे हैं, और आशा है कि आपके परीक्षण के किले पर्याप्त सुरक्षित हैं।

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

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


3
हाँ, लेकिन अपने पहले उदाहरण के बारे में, जिसे आसानी से लिखा जा सकता है: if( !doSomething() ) { puts( "ERROR - doSomething failed" ) ; return ; // or react to failure of doSomething } if( !doSomethingElse() ) { // react to failure of doSomethingElse() }
bobobobo

क्यों नहीं ... लेकिन फिर, मुझे अभी भी doSomething(); doSomethingElse(); ...बेहतर लगता है क्योंकि अगर मुझे / जबकि / आदि को जोड़ने की आवश्यकता है। सामान्य निष्पादन उद्देश्यों के लिए वक्तव्य, मैं उन्हें / जबकि / आदि के साथ मिश्रित नहीं करना चाहता। असाधारण उद्देश्यों के लिए जोड़े गए कथन ... और अपवादों का उपयोग करने के बारे में वास्तविक नियम को फेंकना है , न कि पकड़ने के लिए , कोशिश / पकड़ के बयान आमतौर पर आक्रामक नहीं होते हैं।
पियरसबल ३०'१२

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

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

इस तरह की बहस में उदाहरण बहुत सरल है। आमतौर पर, "doSomething ()" या "doSomethingElse ()" वास्तव में कुछ का प्रदर्शन करते हैं, जैसे कि किसी वस्तु की स्थिति को बदलना। अपवाद कोड ऑब्जेक्ट को पिछली स्थिति में वापस करने की गारंटी नहीं देता है और तब भी कम होता है जब पकड़ थ्रो से बहुत दूर हो ... उदाहरण के रूप में, कल्पना करें doSomething को दो बार कहा जाता है, और फेंकने से पहले एक काउंटर बढ़ाना। आपको यह कैसे पता चलेगा कि अपवाद को पकड़ते समय आपको एक या दो बार कमी करनी चाहिए? सामान्य तौर पर, किसी भी चीज़ के लिए अपवाद सुरक्षित कोड लिखना जो एक खिलौना उदाहरण नहीं है, बहुत कठिन (असंभव?) है।
xryl669

36

मैं वास्तव में दोनों का उपयोग करता हूं।

यदि यह ज्ञात, संभव त्रुटि है, तो मैं रिटर्न कोड का उपयोग करता हूं। यदि यह ऐसा परिदृश्य है जिसे मैं जानता हूं, और होगा, तो एक कोड है जो वापस भेजा जाता है।

अपवाद केवल उन चीजों के लिए उपयोग किए जाते हैं, जिनकी मुझे उम्मीद नहीं है।


जाने के लिए बहुत ही सरल तरीके से +1। कम से कम इसका कम से कम इतना है कि मैं इसे बहुत जल्दी पढ़ सकता हूं। :-)
आशीष गुप्ता

1
" अपवाद केवल उन चीजों के लिए उपयोग किए जाते हैं, जिनकी मुझे उम्मीद नहीं है। " यदि आप उनसे उम्मीद नहीं कर रहे हैं, तो आप उनका उपयोग क्यों या कैसे कर सकते हैं?
अनार खलीलोव

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

क्या एक गैर-जिम्मेदार SQL सर्वर आसानी से "ज्ञात, संभावित त्रुटि" के तहत वर्गीकृत नहीं किया जाएगा?
tkburbidge

21

अध्याय 7 के अनुसार फ्रेमवर्क डिज़ाइन दिशानिर्देशों में "अपवाद" शीर्षक : पुन: प्रयोज्य .NET पुस्तकालयों के लिए कन्वेंशन, मुहावरे, और पैटर्न , कई तर्क दिए गए हैं कि रिटर्न मानों के अपवादों का उपयोग ओ # फ्रेमवर्क जैसे सी # के लिए क्यों आवश्यक है।

शायद यह सबसे सम्मोहक कारण है (पृष्ठ 179):

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


10

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

जब तक आप जो कोड लिख रहे हैं वह समय-महत्वपूर्ण है, तब तक ढेर को खोल देने से जुड़ा ओवरहेड चिंता करने के लिए पर्याप्त महत्वपूर्ण नहीं है।


2
याद रखें कि अपवादों का उपयोग करने से प्रोग्राम विश्लेषण कठिन हो जाता है।
पावेल हजान

7

अपवाद केवल वापस आ जाना चाहिए जहां कुछ ऐसा होता है जिसकी आपको उम्मीद नहीं थी।

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

अपवाद भी बहुत अधिक जानकारी प्रदान कर सकते हैं, और विशेष रूप से अच्छी तरह से 'कुछ गलत हुआ, यहाँ क्या है, एक स्टैक ट्रेस और संदर्भ के लिए कुछ सहायक जानकारी'

यह कहा जा रहा है, एक अच्छी तरह से गणना की गई वापसी कोड परिणामों के एक ज्ञात सेट के लिए उपयोगी हो सकता है, एक सरल 'समारोह के परिणामों की विधियां हैं, और यह सिर्फ इस तरह से चलता है'


6

जावा में, मैं (निम्नलिखित क्रम में) का उपयोग करता हूं:

  1. डिज़ाइन-बाय-कॉन्ट्रैक्ट (यह सुनिश्चित करना कि किसी भी चीज़ को विफल करने से पहले पूर्व शर्त पूरी की जाती है )। यह अधिकांश चीजों को पकड़ता है और मैं इसके लिए एक त्रुटि कोड देता हूं।

  2. प्रसंस्करण कार्य के दौरान त्रुटि कोड लौटना (और यदि आवश्यक हो तो रोलबैक प्रदर्शन करना)।

  3. अपवाद, लेकिन इनका उपयोग केवल अप्रत्याशित चीजों के लिए किया जाता है ।


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

@ PawełHajdan, दावे डिफ़ॉल्ट रूप से अक्षम हैं, मुझे विश्वास है। यह सी के assertसामान के रूप में एक ही समस्या है कि यह उत्पादन कोड में समस्याओं को नहीं पकड़ेगा जब तक कि आप हर समय दावे के साथ न चलें। मैं विकास के दौरान समस्याओं को पकड़ने के एक तरीके के रूप में जोर देता हूं, लेकिन केवल उस सामान के लिए जो लगातार मुखर होगा या नहीं (जैसे स्थिरांक के साथ सामान, चर के साथ सामान नहीं या कुछ और जो रनटाइम में बदल सकता है)।
paxdiablo

और आपके प्रश्न का उत्तर देने के लिए बारह साल। मुझे एक हेल्प डेस्क :-)
paxdiablo

6

रिटर्न कोड मेरे लिए लगभग हर बार " पिट ऑफ सक्सेस " टेस्ट में फेल हो जाते हैं ।

  • रिटर्न कोड की जांच करना भूल जाना बहुत आसान है और फिर बाद में एक रेड-हेरिंग त्रुटि हो सकती है।
  • रिटर्न कोड में कॉल स्टैक, इनर अपवाद जैसे महान डिबगिंग जानकारी नहीं है।
  • रिटर्न कोड प्रचारित नहीं करते हैं, जो ऊपर दिए गए बिंदु के साथ, एक केंद्रीकृत स्थान (आवेदन और थ्रेड स्तर अपवाद हैंडलर) में लॉगिंग के बजाय अत्यधिक और इंटरवॉवन डायग्नोस्टिक लॉगिंग को ड्राइव करता है।
  • रिटर्न कोड नेस्टेड के रूप में गंदे कोड को ड्राइव करने के लिए होते हैं 'यदि' ब्लॉक
  • डेवलपर समय एक अज्ञात मुद्दे पर डिबगिंग में बिताया है जो अन्यथा एक स्पष्ट अपवाद (सफलता का गड्ढा) आईएस महंगा होगा।
  • यदि C # के पीछे की टीम ने नियंत्रण प्रवाह को नियंत्रित करने के अपवादों का इरादा नहीं किया था, तो अपवादों को टाइप नहीं किया जाएगा, कोई "" नहीं होगा जब "कैच स्टेटमेंट पर फ़िल्टर" होगा, और पैरामीटर-कम 'थ्रो' स्टेटमेंट की कोई आवश्यकता नहीं होगी ।

प्रदर्शन के बारे में:

  • अपवाद कम्प्यूटेशनल रूप से महंगा हो सकता है विश्वसनीय बिल्कुल नहीं फेंकने के लिए, लेकिन वे एक कारण के लिए अपवाद कहलाते हैं। स्पीड तुलना हमेशा 100% अपवाद दर मानने का प्रबंधन करती है जो कभी भी नहीं होनी चाहिए। यहां तक ​​कि अगर एक अपवाद 100x धीमा है, तो यह वास्तव में कितना मायने रखता है अगर यह केवल 1% समय होता है?
  • जब तक हम ग्राफिक्स अनुप्रयोगों या कुछ समान के लिए फ्लोटिंग पॉइंट अंकगणितीय बात कर रहे हैं, तब तक डेवलपर समय की तुलना में सीपीयू साइकिल सस्ते होते हैं।
  • समय के दृष्टिकोण से लागत समान तर्क को वहन करती है। डेटाबेस प्रश्नों या वेब सेवा कॉल या फ़ाइल भार के सापेक्ष, सामान्य अनुप्रयोग समय अपवाद समय को बौना कर देगा। 2006 में अपवाद लगभग उप-माइक्रोसेकंड थे
    • मैं सभी नेटवर्कों पर ब्रेक लगाने के लिए अपने डिबगर को सेट करने और अपने कोड को अक्षम करने के लिए .net में काम करने वाले किसी की भी हिम्मत करता हूं और देखता हूं कि कितने अपवाद पहले से ही हो रहे हैं जिनके बारे में आपको पता भी नहीं है।

4

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


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

4

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

अपवाद फेंकने का प्रदर्शन ओवरहेड आपके निर्णय में कोई भूमिका नहीं निभाना चाहिए। यदि आप इसे सही कर रहे हैं, तो आखिरकार, एक अपवाद असाधारण है


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

मैं पूरी तरह से सहमत। ऐसा लगता है कि मैंने पिछले नौ वर्षों में एक या दो चीजें सीखी हैं;)
थॉमस

4

मैं रिटर्न कोड को नापसंद करता हूं क्योंकि वे आपके कोड में मशरूम के लिए निम्न पैटर्न का कारण बनते हैं

CRetType obReturn = CODE_SUCCESS;
obReturn = CallMyFunctionWhichReturnsCodes();
if (obReturn == CODE_BLOW_UP)
{
  // bail out
  goto FunctionExit;
}

जल्द ही एक विधि कॉल जिसमें 4 फ़ंक्शन कॉल होते हैं, त्रुटि हैंडलिंग की 12 लाइनों के साथ फूला हुआ होता है .. जिनमें से कुछ कभी नहीं होगा। यदि और स्विच मामले लाजिमी हैं।

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

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

मैंने 'प्रदर्शन दंड' प्रतिवाद के बारे में थोड़ा शिकार किया है .. C ++ / COM दुनिया में अधिक लेकिन नई भाषाओं में, मुझे लगता है कि अंतर इतना नहीं है। किसी भी स्थिति में, जब कोई चीज ऊपर उठती है, तो प्रदर्शन संबंधी चिंताएँ बैकबर्नर पर आ जाती हैं :)


3

किसी भी सभ्य संकलक या रनटाइम वातावरण अपवाद के साथ एक महत्वपूर्ण जुर्माना नहीं लगता है। यह कमोबेश एक GOTO के कथन की तरह है जो अपवाद हैंडलर से कूदता है। इसके अलावा, एक रनटाइम वातावरण (जैसे जेवीएम) द्वारा पकड़े गए अपवादों को अलग करना और बग को बहुत आसान तरीके से ठीक करने में मदद करता है। मैं किसी भी दिन सी में एक segfault पर जावा में एक NullPointerException ले जाऊँगा।


2
अपवाद बेहद महंगे हैं। संभावित अपवाद संचालकों को खोजने के लिए उन्हें ढेर पर चलना होगा। यह स्टैक वॉक सस्ता नहीं है। यदि स्टैक ट्रेस बनाया गया है, तो यह और भी महंगा है, क्योंकि तब पूरे स्टैक को पार्स किया जाना चाहिए।
डेरेक पार्क

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

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

मैं इस बात से सहमत हूं कि अपवादों के डिबगिंग लाभ अक्सर प्रदर्शन लागत के लिए बनाते हैं, हालांकि।
डेरेक पार्क

1
डेरक पार्क, अपवाद तब महंगा होता है जब वे होते हैं। यही कारण है कि उनका अत्यधिक उपयोग नहीं किया जाना चाहिए। लेकिन जब वे ऐसा नहीं करते हैं, तो उनके पास लगभग कुछ भी नहीं होता है।
पियरसबल

3

मेरे पास नियमों का एक सरल सेट है:

1) उन चीजों के लिए रिटर्न कोड का उपयोग करें जिनकी आप अपेक्षा करते हैं कि आपका तत्काल कॉलर प्रतिक्रिया करे।

2) उन त्रुटियों के लिए अपवादों का उपयोग करें जो दायरे में व्यापक हैं, और उचित हो सकता है कि कॉलर के ऊपर कुछ स्तरों द्वारा नियंत्रित किया जाए, ताकि त्रुटि के बारे में जागरूकता कई परतों के माध्यम से समाप्त न हो, जिससे कोड अधिक जटिल हो जाए।

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


3

मैं अपवाद के अलावा, और गैर-असाधारण परिस्थितियों में अजगर में अपवाद का उपयोग करता हूं।

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

try:
    dataobj = datastore.fetch(obj_id)
except LookupError:
    # could not find object, create it.
    dataobj = datastore.create(....)

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

यहाँ एक और उदाहरण है, जहाँ अपवाद 'उपयोगी' हैं, ऐसे में फाइल सिस्टम से निपटने के लिए कोड लिखने के लिए उपयोगी है जो कि दौड़ की स्थिति के अधीन नहीं है।

# wrong way:
if os.path.exists(directory_to_remove):
    # race condition is here.
    os.path.rmdir(directory_to_remove)

# right way:
try: 
    os.path.rmdir(directory_to_remove)
except OSError:
    # directory didn't exist, good.
    pass

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


दूसरा उदाहरण भ्रामक है। माना जाता है कि गलत तरीका गलत है क्योंकि os.path.rmdir कोड को अपवाद फेंकने के लिए डिज़ाइन किया गया है। रिटर्न कोड प्रवाह में सही कार्यान्वयन 'अगर rmdir (...) == विफल: पास'
MaR

3

मेरा मानना ​​है कि रिटर्न कोड कोड शोर में जोड़ता है। उदाहरण के लिए, मुझे हमेशा रिटर्न कोड के कारण COM / ATL कोड के रूप से नफरत थी। कोड की प्रत्येक पंक्ति के लिए एक HRESULT जांच होनी चाहिए। मैं समझता हूं कि त्रुटि वापसी कोड COM के आर्किटेक्ट द्वारा किए गए बुरे फैसलों में से एक है। कोड का तार्किक समूहन करना कठिन हो जाता है, इस प्रकार कोड की समीक्षा कठिन हो जाती है।

जब हर पंक्ति रिटर्न कोड के लिए एक स्पष्ट जाँच होती है, तो मैं प्रदर्शन तुलना के बारे में निश्चित नहीं हूं।


1
COM वाड को उन भाषाओं द्वारा प्रयोग करने योग्य बनाया गया है जो अपवादों का समर्थन नहीं करते हैं।
केविन

यह एक अच्छी बात है। यह स्क्रिप्टिंग भाषाओं के लिए त्रुटि कोड से निपटने के लिए समझ में आता है। कम से कम VB6 एरर ऑब्जेक्ट में उन्हें कूटबद्ध करने के साथ त्रुटि कोड विवरण को अच्छी तरह से छुपाता है, जो कुछ हद तक क्लीनर कोड में मदद करता है।
rpattabi

मैं असहमत हूं: VB6 केवल अंतिम त्रुटि को लॉग करता है। बदनाम "त्रुटि फिर से शुरू" के साथ संयुक्त, आप अपनी समस्या के स्रोत को पूरी तरह से याद करेंगे, जब तक आप इसे नहीं देखेंगे। ध्यान दें कि यह Win32 APII में त्रुटि से निपटने का आधार है (GetLastError फ़ंक्शन देखें)
paercebal

2

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


2

एक बड़ा अंतर यह है कि अपवाद आपको एक त्रुटि को संभालने के लिए मजबूर करते हैं, जबकि त्रुटि वापसी कोड अनियंत्रित हो सकते हैं।

त्रुटि वापसी कोड, यदि भारी उपयोग किया जाता है, तो बहुत ही बदसूरत कोड भी पैदा कर सकता है यदि इस फॉर्म के समान परीक्षण बहुत सारे हैं:

if(function(call) != ERROR_CODE) {
    do_right_thing();
}
else {
    handle_error();
}

व्यक्तिगत रूप से मैं उन त्रुटियों के अपवादों का उपयोग करना पसंद करता हूं जिन्हें कॉल कोड द्वारा किया जाना चाहिए और उन पर केवल "अपेक्षित विफलताओं" के लिए त्रुटि कोड का उपयोग करना चाहिए, जहां कुछ लौटाना वास्तव में वैध और संभव है।


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

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

2

रिटर्न कोड पर अपवाद पसंद करने के कई कारण हैं:

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

2

अपवाद त्रुटि से निपटने के लिए नहीं हैं, IMO। अपवाद सिर्फ इतना है कि; असाधारण घटनाएं जिनकी आपको उम्मीद नहीं थी। मैं कहता हूं सावधानी के साथ प्रयोग करें।

त्रुटि कोड ठीक हो सकता है, लेकिन एक विधि से 404 या 200 वापस करना खराब है, आईएमओ। इसके बजाय enums (.Net) का उपयोग करें, जो अन्य डेवलपर्स के लिए कोड को अधिक पठनीय और उपयोग करने में आसान बनाता है। इसके अलावा, आपको संख्याओं और विवरणों पर तालिका बनाए रखने की आवश्यकता नहीं है।

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

try{
    db.UpdateAll(somevalue);
}
catch (Exception ex) {
    logger.Exception(ex, "UpdateAll method failed");
    throw;
}

इसलिए जब तक आप अपवाद को जारी रखने दें तब तक यह ठीक है। एक अन्य उदाहरण यह है:

try{
    dbHasBeenUpdated = db.UpdateAll(somevalue); // true/false
}
catch (ConnectionException ex) {
    logger.Exception(ex, "Connection failed");
    dbHasBeenUpdated = false;
}

यहां मैं वास्तव में अपवाद को संभालता हूं; अद्यतन विधि विफल होने पर मैं कोशिश-कैच के बाहर क्या करता हूं, एक और कहानी है, लेकिन मुझे लगता है कि मेरी बात बन गई है। :)

फिर ट्रायल-कैच-एंड-एंटी-पैटर्न क्यों है? यहाँ पर क्यों:

try{
    db.UpdateAll(somevalue);
}
catch (Exception ex) {
    logger.Exception(ex, "UpdateAll method failed");
    throw;
}
finally {
    db.Close();
}

यदि डीबी ऑब्जेक्ट पहले ही बंद हो गया है तो क्या होगा? एक नया अपवाद फेंक दिया गया है और इसे संभालना होगा! यह बेहतर है:

try{
    using(IDatabase db = DatabaseFactory.CreateDatabase()) {
        db.UpdateAll(somevalue);
    }
}
catch (Exception ex) {
    logger.Exception(ex, "UpdateAll method failed");
    throw;
}

या, यदि db ऑब्जेक्ट IDisposable को कार्यान्वित नहीं करता है तो ऐसा करें:

try{
    try {
        IDatabase db = DatabaseFactory.CreateDatabase();
        db.UpdateAll(somevalue);
    }
    finally{
        db.Close();
    }
}
catch (DatabaseAlreadyClosedException dbClosedEx) {
    logger.Exception(dbClosedEx, "Database connection was closed already.");
}
catch (Exception ex) {
    logger.Exception(ex, "UpdateAll method failed");
    throw;
}

वैसे भी मेरे 2 सेंट है! :)


यह अजीब होगा यदि कोई वस्तु है। क्लोज़ () लेकिन नहीं है। डीसपोज़ करें ()
abatishchev

मैं केवल उदाहरण के रूप में बंद () का उपयोग कर रहा हूं। इसे बेझिझक कुछ और समझिए। जैसा कि मैं राज्य; यदि उपलब्ध हो तो पैटर्न का उपयोग किया जाना चाहिए (दोह!)। इस पाठ्यक्रम का तात्पर्य यह है कि वर्ग आईडीआईसपोजेबल को लागू करता है और जैसे आप डिस्पोज को बुला सकते हैं।
noocyte

1

मैं केवल अपवादों का उपयोग करता हूं, कोई रिटर्न कोड नहीं। मैं यहाँ जावा के बारे में बात कर रहा हूँ।

मेरे द्वारा पालन किया जाने वाला सामान्य नियम है यदि मेरे पास एक विधि है, doFoo()तो यह इस प्रकार है कि यदि यह "फू" नहीं करता है, जैसा कि यह था, तो कुछ असाधारण हुआ है और एक अपवाद को फेंक दिया जाना चाहिए।


1

अपवादों के बारे में मुझे एक बात का डर है कि एक अपवाद को फेंकने से कोड प्रवाह खराब हो जाएगा। उदाहरण के लिए यदि आप

void foo()
{
  MyPointer* p = NULL;
  try{
    p = new PointedStuff();
    //I'm a module user and  I'm doing stuff that might throw or not

  }
  catch(...)
  {
    //should I delete the pointer?
  }
}

या इससे भी बुरी बात यह है कि अगर मुझे कुछ ऐसा नहीं करना चाहिए जो मेरे पास नहीं है, लेकिन मैं बाकी क्लीनअप करने से पहले उसे पकड़ने के लिए तैयार हो गया। गरीब उपयोगकर्ता IMHO पर बहुत अधिक भार डाला।


यह वह है जो <code> आखिर </ code> स्टेटमेंट के लिए है। लेकिन, अफसोस, यह C ++ मानक में नहीं है ...
थॉमस

C ++ में आप अंगूठे का नियम को "प्राप्त संसाधनों construcotor में रहना चाहिए और उन्हें destrucotor में रिलीज के लिए इस विशेष मामले auto_ptr सिर्फ prefectly
सर्ज

थॉमस, तुम गलत हो। C ++ अंत में नहीं है क्योंकि इसे इसकी आवश्यकता नहीं है। इसकी जगह RAII है। सर्ज का समाधान RAII का उपयोग कर एक समाधान है।
पियरसबल

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

1

अपवाद बनाम रिटर्न कोड तर्क में मेरा सामान्य नियम:

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

जब आप l10n / i18n करते हैं तो आप अपवाद का उपयोग नहीं कर सकते, इसका कोई कारण नहीं है। अपवादों में स्थानीय जानकारी भी हो सकती है।
gizmo

1

मुझे अपवादों की तुलना में कम बदसूरत होने के लिए रिटर्न कोड नहीं मिलते हैं। अपवाद के साथ, आपके पास वह स्थान है try{} catch() {} finally {}जहां आपके पास रिटर्न कोड हैं if(){}। मैं पोस्ट में दिए गए कारणों से अपवादों से डरता था; आपको पता नहीं है कि सूचक को साफ करने की आवश्यकता है, तो आपके पास क्या है। लेकिन मुझे लगता है कि जब आप रिटर्न कोड की बात करते हैं तो आपको वही समस्याएं होती हैं। जब तक आप फ़ंक्शन / विधि के बारे में कुछ विवरण नहीं जानते, आपको मापदंडों की स्थिति का पता नहीं चलता है।

भले ही, यदि संभव हो तो आपको त्रुटि को संभालना होगा। आप एक रिटर्न कोड को अनदेखा करने और प्रोग्राम को सेगफ़ॉल्ट करने की अनुमति देने के साथ ही शीर्ष स्तर पर आसानी से अपवाद छोड़ सकते हैं।

मुझे परिणामों के लिए एक मान (गणना) वापस करने का विचार पसंद है और एक असाधारण मामले के लिए एक अपवाद है।


0

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

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


0

मैं आम तौर पर रिटर्न कोड पसंद करता हूं क्योंकि वे कॉलर को यह तय करने देते हैं कि क्या विफलता असाधारण है

यह दृष्टिकोण अमृत भाषा में विशिष्ट है।

# I care whether this succeeds. If it doesn't return :ok, raise an exception.
:ok = File.write(path, content)

# I don't care whether this succeeds. Don't check the return value.
File.write(path, content)

# This had better not succeed - the path should be read-only to me.
# If I get anything other than this error, raise an exception.
{:error, :erofs} = File.write(path, content)

# I want this to succeed but I can handle its failure
case File.write(path, content) do
  :ok => handle_success()
  error => handle_error(error)
end

लोगों ने उल्लेख किया कि रिटर्न कोड आपको बहुत से नेस्टेड ifस्टेटमेंट दे सकते हैं, लेकिन इसे बेहतर सिंटैक्स के साथ संभाला जा सकता है। अमृत ​​में, withबयान हमें आसानी से किसी भी विफलताओं से खुश-पथ वापसी मूल्य की एक श्रृंखला को अलग करने देता है।

with {:ok, content} <- get_content(),
  :ok <- File.write(path, content) do
    IO.puts "everything worked, happy path code goes here"
else
  # Here we can use a single catch-all failure clause
  # or match every kind of failure individually
  # or match subsets of them however we like
  _some_error => IO.puts "one of those steps failed"
  _other_error => IO.puts "one of those steps failed"
end

अमृत ​​में अभी भी कार्य हैं जो अपवादों को बढ़ाते हैं। अपने पहले उदाहरण पर वापस जाते हुए, मैं इनमें से कोई भी एक अपवाद बढ़ा सकता था यदि फ़ाइल नहीं लिखी जा सकती।

# Raises a generic MatchError because the return value isn't :ok
:ok = File.write(path, content)

# Raises a File.Error with a descriptive error message - eg, saying
# that the file is read-only
File.write!(path, content)

यदि मैं, फोन करने वाले के रूप में, जानता हूं कि मैं एक त्रुटि उठाना चाहता हूं यदि लेखन विफल रहता है, तो मैं File.write!इसके बजाय कॉल करना चुन सकता हूं File.write। या मैं File.writeअसफलता के विभिन्न संभावित कारणों में से प्रत्येक को कॉल करना और संभालना चुन सकता हूं ।

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

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