मैं इस उत्तर के साथ अन्य भाषाओं के पायथनस्टास (जैसा कि मुझे पता नहीं है कि मैं पायथन का अधिक उपयोग नहीं करता हूं) या अन्य भाषाओं के क्रोध का आह्वान कर सकता हूं, लेकिन मेरी राय में अधिकांश कार्यों में ब्लॉक नहीं होना चाहिए catch
, आदर्श रूप से बोलना। यह दिखाने के लिए कि, 80 के दशक के उत्तरार्ध और 90 के दशक की शुरुआत में टर्बो सी के साथ काम करने के दौरान मुझे उस तरह के मैनुअल त्रुटि कोड प्रसार के विपरीत करना पड़ा था।
तो मान लें कि हमारे पास छवि को लोड करने के लिए एक फ़ंक्शन है या उपयोगकर्ता की प्रतिक्रिया में ऐसा कुछ है जो लोड करने के लिए एक छवि फ़ाइल का चयन करता है, और यह सी और असेंबली में लिखा गया है:
मैंने कुछ निम्न-स्तर के कार्यों को छोड़ दिया, लेकिन हम देख सकते हैं कि मैंने विभिन्न श्रेणियों के कार्यों की पहचान की है, जो रंग-कोडित हैं, जो त्रुटि-हैंडलिंग के संबंध में उनकी जिम्मेदारियों पर आधारित है।
विफलता और रिकवरी के बिंदु
अब मैं "विफलताओं का संभावित बिंदु" (जो कि throw
, अर्थात) और "त्रुटि पुनर्प्राप्ति और रिपोर्ट" फ़ंक्शन (जो कि catch
, अर्थात) को कॉल करना मुश्किल था ।
उन कार्यों को हमेशा लिखने के लिए सही ढंग से पहले अपवाद हैंडलिंग उपलब्ध था एक समारोह है कि स्मृति को आबंटित करने में नाकाम रहने की तरह एक बाहरी विफलता में चला सकते हैं, सिर्फ एक लौट सकते हैं के बाद से तुच्छ थे NULL
या 0
या -1
या एक वैश्विक त्रुटि कोड या इस संबंध में कुछ निर्धारित किया है। और त्रुटि पुनर्प्राप्ति / रिपोर्टिंग हमेशा आसान थी क्योंकि एक बार जब आपने कॉल स्टैक को एक ऐसे बिंदु पर काम किया था जहां यह पुनर्प्राप्त करने और विफलता की रिपोर्ट करने के लिए समझ में आया, तो आप बस त्रुटि कोड और / या संदेश लेते हैं और इसे उपयोगकर्ता को रिपोर्ट करते हैं। और इस पदानुक्रम के पत्ते पर स्वाभाविक रूप से एक फ़ंक्शन जो कभी नहीं हो सकता है, कभी भी असफल नहीं होता है कि यह भविष्य में कैसे बदल जाता है ( Convert Pixel
) सही तरीके से लिखने के लिए मृत है (कम से कम त्रुटि से निपटने के संबंध में)।
त्रुटि प्रचार
हालांकि, मानव त्रुटि के लिए थकाऊ कार्यों में त्रुटि प्रसारकर्ता थे , जो सीधे विफलता में नहीं चले थे , लेकिन उन कार्यों को कहा जाता है जो पदानुक्रम में कहीं गहरे विफल हो सकते हैं। उस बिंदु पर, Allocate Scanline
एक विफलता को संभालना पड़ सकता है malloc
और फिर एक त्रुटि को वापस कर सकता है Convert Scanlines
, फिर Convert Scanlines
उस त्रुटि की जांच करनी होगी और उसे नीचे Decompress Image
, फिर Decompress Image->Parse Image
, और Parse Image->Load Image
, और Load Image
उपयोगकर्ता-अंत कमांड में भेजना होगा जहां त्रुटि की रिपोर्ट की गई है। ।
यह वह जगह है जहाँ बहुत सारे मनुष्य गलतियाँ करते हैं क्योंकि यह केवल एक त्रुटि प्रसारकर्ता को जांचने में विफल होने के लिए ले जाता है और जब यह ठीक से त्रुटि को संभालने के लिए आता है, तो कार्य के पूरे पदानुक्रम के लिए त्रुटि को पास करना पड़ता है।
इसके अलावा, यदि त्रुटि कोड फ़ंक्शंस द्वारा लौटाए जाते हैं, तो हम बहुत अधिक क्षमता खो देते हैं, कहते हैं, हमारे कोडबेस के 90%, सफलता पर ब्याज के मूल्यों को वापस करने के लिए क्योंकि इतने सारे फ़ंक्शंस को एक त्रुटि कोड वापस करने के लिए अपना वापसी मूल्य आरक्षित करना होगा असफलता ।
मानव त्रुटि को कम करना: वैश्विक त्रुटि कोड
तो हम मानवीय त्रुटि की संभावना को कैसे कम कर सकते हैं? यहाँ पर मैं कुछ C प्रोग्रामरों के क्रोध को भी रोक सकता हूँ, लेकिन मेरी राय में एक तत्काल सुधार Open Open with जैसे वैश्विक त्रुटि कोड का उपयोग करना है glGetError
। यह कम से कम कार्यों को सफलता पर ब्याज के सार्थक मूल्यों को लौटाने के लिए मुक्त करता है। इस थ्रेड को सुरक्षित और कुशल बनाने के तरीके हैं जहां त्रुटि कोड एक थ्रेड के लिए स्थानीयकृत है।
कुछ ऐसे मामले भी होते हैं, जिनमें कोई फ़ंक्शन किसी त्रुटि में चल सकता है, लेकिन पिछली त्रुटि की खोज के परिणामस्वरूप समय से पहले लौटने से पहले इसे थोड़ी देर के लिए रखना अपेक्षाकृत हानिरहित है। यह हर एक फ़ंक्शन में किए गए 90% फ़ंक्शन कॉल के खिलाफ त्रुटियों की जांच किए बिना ऐसा करने की अनुमति देता है, इसलिए यह अभी भी इतनी सावधानी के बिना उचित त्रुटि से निपटने की अनुमति दे सकता है।
मानव त्रुटि को कम करना: अपवाद-हैंडलिंग
हालाँकि, उपरोक्त समाधान को मैनुअल त्रुटि प्रसार के नियंत्रण प्रवाह पहलू से निपटने के लिए अभी भी बहुत सारे कार्यों की आवश्यकता है, भले ही इससे मैन्युअल if error happened, return error
प्रकार की लाइनों की संख्या कम हो गई हो । यह पूरी तरह से समाप्त नहीं होगा क्योंकि अभी भी अक्सर एक त्रुटि के लिए कम से कम एक जगह की जाँच करने की आवश्यकता होती है और लगभग हर एक त्रुटि प्रसार फ़ंक्शन के लिए वापस लौटता है। तो यह तब होता है जब अपवाद (हैंडलिंग) दिन को बचाने के लिए तस्वीर में आता है (सॉर्टा)।
लेकिन यहां अपवाद-हैंडलिंग का मूल्य मैनुअल त्रुटि प्रसार के नियंत्रण प्रवाह पहलू से निपटने की आवश्यकता को मुक्त करना है। इसका मतलब है कि इसका मूल्य catch
आपके कोडबेस में ब्लॉकों के एक बोटलोड को लिखने से बचने की क्षमता से जुड़ा हुआ है । उपरोक्त आरेख में, एक ही स्थान जिसमें एक catch
ब्लॉक होना चाहिए था , Load Image User Command
जहां त्रुटि रिपोर्ट की गई है। और कुछ नहीं आदर्श रूप से catch
कुछ भी होना चाहिए क्योंकि अन्यथा यह थकाऊ और त्रुटि कोड हैंडलिंग के रूप में त्रुटि के रूप में शुरू हो रहा है।
इसलिए यदि आप मुझसे पूछते हैं, यदि आपके पास एक कोडबेस है जो वास्तव में अपवाद-तरीके से एक सुरुचिपूर्ण तरीके से लाभ उठाता है, तो इसमें न्यूनतमcatch
ब्लॉक की संख्या होनी चाहिए (न्यूनतम से मेरा मतलब शून्य नहीं है, लेकिन प्रत्येक अद्वितीय उच्च के लिए एक जैसा है- अंत उपयोगकर्ता संचालन जो विफल हो सकता है, और संभवतः कम भी हो सकता है यदि सभी उच्च-अंत उपयोगकर्ता संचालन एक केंद्रीय कमांड सिस्टम के माध्यम से लागू किए जाते हैं)।
संसाधन सफाई
हालांकि, अपवाद-हैंडलिंग केवल निष्पादन के सामान्य प्रवाह से अलग असाधारण पथों में त्रुटि प्रसार के नियंत्रण प्रवाह पहलुओं से मैन्युअल रूप से निपटने से बचने की आवश्यकता को हल करता है। अक्सर एक फ़ंक्शन जो एक त्रुटि प्रचारक के रूप में कार्य करता है, भले ही यह ईएच के साथ स्वचालित रूप से ऐसा करता हो, फिर भी इसे नष्ट करने के लिए आवश्यक कुछ संसाधनों का अधिग्रहण कर सकता है। उदाहरण के लिए, ऐसा फ़ंक्शन एक अस्थायी फ़ाइल खोल सकता है जिसे फ़ंक्शन से लौटने से पहले बंद करने की आवश्यकता होती है, चाहे जो भी हो, या किसी म्यूटेक्स को लॉक करने के लिए उसे कोई फर्क नहीं पड़ता है कि क्या अनलॉक करना है।
इसके लिए, मैं सभी प्रकार की भाषाओं के बहुत सारे प्रोग्रामर के क्रोध का आह्वान कर सकता हूं, लेकिन मुझे लगता है कि C ++ का दृष्टिकोण आदर्श है। भाषा विध्वंसक का परिचय देती है जो एक नियतात्मक फैशन में आह्वान करती है, एक वस्तु तुरंत दायरे से बाहर हो जाती है। इसके कारण, C ++ कोड, जो कहता है, एक म्यूटेक्स को एक स्कोप्ड म्यूटेक्स ऑब्जेक्ट के माध्यम से लॉक करता है, एक विध्वंसक के साथ इसे मैन्युअल रूप से अनलॉक करने की आवश्यकता नहीं है, क्योंकि ऑब्जेक्ट के दायरे से बाहर जाने के बाद यह स्वचालित रूप से अनलॉक हो जाएगा, चाहे जो भी हो (भले ही कोई अपवाद हो) का सामना करना पड़ा)। इसलिए स्थानीय संसाधन सफाई से निपटने के लिए वास्तव में अच्छी तरह से लिखित सी ++ कोड की कोई आवश्यकता नहीं है।
ऐसी भाषाएं जिनमें विनाशकों की कमी होती है, उन्हें finally
स्थानीय संसाधनों को मैन्युअल रूप से साफ़ करने के लिए ब्लॉक का उपयोग करने की आवश्यकता हो सकती है । उस ने कहा, यह अभी भी अपने कोड को मैन्युअल त्रुटि प्रसार के साथ लिटाने के लिए धड़कता है, बशर्ते कि आपके पास catch
सभी फ्रिकिंग स्थानों पर अपवाद न हों ।
बाहरी साइड इफेक्ट्स को उलट देना
यह वह जगह है हल करने के लिए सबसे कठिन वैचारिक समस्या। यदि कोई फ़ंक्शन, चाहे वह त्रुटि प्रचारक हो या विफलता का बिंदु बाहरी साइड इफेक्ट्स का कारण बनता है, तो उसे वापस रोल करने की आवश्यकता है या सिस्टम को वापस करने के लिए उन दुष्प्रभावों को "पूर्ववत करें" जैसा कि ऑपरेशन के बाद कभी नहीं हुआ, " आधा-वैध "राज्य जहां ऑपरेशन आधा सफल रहा। मुझे ऐसी भाषाओं के बारे में पता है जो इस वैचारिक समस्या को उन भाषाओं के अलावा बहुत आसान बनाती हैं, जो पहली बार बाहरी कार्यों के लिए सबसे अधिक कार्यों की आवश्यकता को कम करती हैं, जैसे कि कार्यात्मक भाषाएं जो अपरिवर्तनीयता और लगातार डेटा संरचनाओं के चारों ओर घूमती हैं।
यहाँ finally
निश्चित रूप से सबसे सुंदर समाधानों में से एक है वहाँ की भाषा में समस्या का उत्परिवर्तन और साइड इफेक्ट्स के इर्द-गिर्द घूमना, क्योंकि अक्सर इस प्रकार के तर्क किसी विशेष कार्य के लिए बहुत विशिष्ट होते हैं और "रिसोर्स क्लीनअप" की अवधारणा को इतना अच्छा नहीं बनाते हैं। "। और मैं finally
इन मामलों में उदारतापूर्वक उपयोग करने की सलाह देता हूं ताकि यह सुनिश्चित किया जा सके कि आपका फ़ंक्शन उन भाषाओं में दुष्प्रभावों को उलट देता है जो इसका समर्थन करते हैं, भले ही आपको catch
ब्लॉक की आवश्यकता हो या न हो , और यदि आप मुझसे पूछें, तो अच्छी तरह से लिखे गए कोड की न्यूनतम संख्या होनी चाहिए catch
ब्लॉक, और सभी catch
ब्लॉक उन जगहों पर होना चाहिए जहां यह ऊपर के आरेख के साथ सबसे अधिक समझ में आता है Load Image User Command
)।
सपना की भाषा
हालांकि, आईएमओ finally
साइड इफेक्ट रिवर्सल के लिए आदर्श के करीब है , लेकिन काफी नहीं। हमें boolean
समय से पहले निकलने (फेंके गए अपवाद या अन्यथा से) के मामले में प्रभावी रूप से साइड इफेक्ट्स को रोल करने के लिए एक वैरिएबल लागू करने की आवश्यकता है , जैसे:
bool finished = false;
try
{
// Cause external side effects.
...
// Indicate that all the external side effects were
// made successfully.
finished = true;
}
finally
{
// If the function prematurely exited before finishing
// causing all of its side effects, whether as a result of
// an early 'return' statement or an exception, undo the
// side effects.
if (!finished)
{
// Undo side effects.
...
}
}
अगर मैं कभी भी एक भाषा डिजाइन कर सकता हूं, तो इस समस्या को हल करने का मेरा सपना तरीका उपरोक्त कोड को स्वचालित करने के लिए होगा:
transaction
{
// Cause external side effects.
...
}
rollback
{
// This block is only executed if the above 'transaction'
// block didn't reach its end, either as a result of a premature
// 'return' or an exception.
// Undo side effects.
...
}
... विध्वंसक के साथ स्थानीय संसाधनों की सफाई को स्वचालित करने के लिए, जिससे हमें केवल जरूरत है transaction
, rollback
और catch
(हालांकि मैं अभी भी जोड़ना चाहूंगा finally
, कहते हैं, सी संसाधनों के साथ काम करना जो खुद को साफ नहीं करते हैं)। हालांकि, finally
एक boolean
चर के साथ इस सीधी बनाने के लिए निकटतम चीज है जो मैंने पाया है कि अब तक मेरी सपनों की भाषा में कमी है। इसके लिए मैंने जो दूसरा सबसे सीधा हल खोजा है वह है C ++ और D जैसी भाषाओं में स्कोप गार्ड्स , लेकिन मैंने हमेशा स्कोप गार्ड्स को थोड़े अजीब तरीके से पाया है क्योंकि यह "रिसोर्स क्लीनअप" और "साइड इफेक्ट रिवर्सल" के विचार को दोष देता है। मेरी राय में वे एक अलग तरीके से निपटने के लिए बहुत विशिष्ट विचार हैं।
किसी भाषा का मेरा छोटा पाइप सपना भी अपरिवर्तनीयता और लगातार डेटा संरचनाओं के चारों ओर घूमता है, ताकि इसे बहुत आसान बना दिया जा सके, हालांकि आवश्यक कार्यों को पूरा करने के लिए कुशल कार्यों को गहराई से कॉपी नहीं करना पड़ता है। कोई दुष्प्रभाव नहीं।
निष्कर्ष
तो वैसे भी, मेरी रैंबलिंग के साथ, मुझे लगता है try/finally
कि सॉकेट को बंद करने के लिए आपका कोड ठीक है और महान विचार है कि पायथन में सी + + विनाशकर्ताओं के बराबर नहीं है, और मुझे व्यक्तिगत रूप से लगता है कि आपको उन जगहों के लिए उदारता से उपयोग करना चाहिए जो रिवर्स साइड इफेक्ट्स की आवश्यकता होती है और उन स्थानों की संख्या को कम करें जहां आपको उन catch
स्थानों पर जाना है जहां यह सबसे अधिक समझ में आता है।