प्रोग्रामर आम तौर पर बिल्कुल सही सॉफ्टवेयर लिखने की कोशिश करते हैं, और आम तौर पर नाकाम रहते हैं।
कभी-कभी चीज़ें अचानक गलत हो जाती हैं, और हमें उनसे निपटना आना चाहिए।
कुछ भाषा डिज़ाइनर मानते हैं कि प्राथमिकता यह है कि एरर को जल्द से जल्द पकड़ा जाए, और फिर डिबगिंग में मदद के लिए जानकारी देने वाला संदेश दिखाकर प्रोग्राम चलाना रोक दिया जाए।
डेटा साइंस की भाषाएँ आम तौर पर ज़्यादा बारीक तरीका अपनाती हैं। कुछ एरर इतनी गंभीर होती हैं कि प्रोग्राम को तुरंत रोकना ज़रूरी हो जाता है, लेकिन अक्सर बेहतर यह होता है कि समस्या को चिह्नित करके बाद में निपटाने के लिए छोड़ दिया जाए और प्रोग्राम चलता रहे।
शून्यता कॉन्सेप्ट में हमने देखा था कि Julia उन वैल्यू के लिए कई तरह के प्लेसहोल्डर देती है जो समस्या पैदा कर सकती हैं: missing, NaN और Inf।
किसी खास स्थिति में ये, प्रोग्राम को रोक देने से बेहतर तरीका हैं या नहीं, यह प्रोग्रामर के फैसले की बात है।
नामकरण की एक बात विवरण में उतरने से पहले: Julia का डॉक्युमेंटेशन "एरर" और "एक्सेप्शन" शब्दों को काफी हद तक एक-दूसरे की जगह इस्तेमाल होने वाले शब्द मानता है। नीचे लिखी बातें भी उतनी ही असंगत हो सकती हैं।
सिलेबस में अब तक आपने Julia के बहुत सारे एरर संदेश ज़रूर देखे होंगे। जैसे:
julia> Int(3.14)
ERROR: InexactError: Int64(3.14)
किसी दशमलव संख्या को पूर्णांक में बदलने पर सटीकता की कमी आती है, इसलिए हमें InexactError मिलती है।
InexactError एक टाइप है, उन कई टाइप में से एक (फिलहाल 25) जो Julia में मानक रूप से पहले से मौजूद हैं।
ये सभी Exception के सबटाइप हैं:
julia> supertype(InexactError)
Exception
throw()कुछ मानक एरर टाइप अपने कोड में पैदा करने के काम आ सकते हैं।
सभी कंक्रीट टाइप की तरह इन एरर के भी कंस्ट्रक्टर होते हैं। ये अलग-अलग तरह के आर्गुमेंट लेते हैं, इसलिए जो इस्तेमाल करना हो उसके लिए डॉक्युमेंटेशन देखिए।
julia> DomainError(42, "out of range")
DomainError(42, "out of range")
एरर इस्तेमाल करने के लिए, कंस्ट्रक्टर को throw() फंक्शन में लपेटिए:
julia> throw(DomainError(42, "out of range"))
ERROR: DomainError with 42:
out of range
error()जल्दी में काम निकालने के लिए error() फंक्शन सुविधाजनक हो सकता है।
यह एक स्ट्रिंग (या स्ट्रिंग के हिस्से) आर्गुमेंट के तौर पर लेता है:
julia> happy = false;
julia> happy || error("😞 something went wrong")
ERROR: 😞 something went wrong
सिद्धांत में नए एरर टाइप बनाना बहुत आसान है।
बस Exception का एक और सबटाइप जोड़ दीजिए:
julia> struct MyError <: Exception end
julia> throw(MyError)
ERROR: MyError
असेर्शन का मूल विचार यह है कि "यह दावा सही होना चाहिए, इसलिए अगर यह गलत निकले तो ज़ोर से शिकायत कीजिए।" इसका फायदा मुख्य रूप से डिबगिंग के दौरान होता है, क्योंकि प्रोडक्शन कोड में कभी कोई असेर्शन फेल नहीं होना चाहिए।
टाइप कॉन्सेप्ट में हमने देखा था कि हम टाइप असेर्शन जोड़ सकते हैं, जैसे किसी फंक्शन का रिटर्न टाइप जाँचने के लिए।
julia> 42::Number
42
julia> "two"::Number
ERROR: TypeError: in typeassert, expected Number, got a value of type String
आम तौर पर, @assert मैक्रो की मदद से हम ऐसा कोई भी एक्सप्रेशन जाँच सकते हैं जिसका मान बूलियन निकलता हो:
julia> n = 22;
julia> @assert isodd(n) "n must be odd"
ERROR: AssertionError: n must be odd
try...catch
कुछ एरर अनिवार्य रूप से घातक होती हैं, लेकिन अक्सर हम उम्मीद करते हैं कि प्रोग्राम सहज ही संभल जाएगा।
डिफ़ॉल्ट रूप से, एरर मौजूदा फंक्शन को तुरंत रोक देती है, और वह एरर (साथ में जानकारी देने वाला संदेश) उस फंक्शन को भेज दी जाती है जिसने इसे कॉल किया था।
यही सिलसिला कॉल स्टैक में ऊपर तक चलता रहता है, जब तक कि टॉप-लेवल कोड किसी एरर संदेश के साथ रुक न जाए।
किसी भी चरण में एरर को try...catch ब्लॉक से पकड़ा जा सकता है, जो उसे संभालने की कोशिश करता है।
julia> n = -1;
julia> try
log_n = log(n)
catch problem
if problem isa DomainError # number out of range
# See next section for more on @warn and @info
@warn "you may have supplied a negative real number: $n"
@info "trying with complex argument"
log_n = log(Complex(n)) # fallback calculation
elseif problem isa MethodError # no idea what n is
@error "please supply a valid argument"
else
rethrow() # the error could be anything else
end
end
┌ Warning: you may have supplied a negative real number: -1
└ @ Main REPL[3]:5
[ Info: trying with complex argument
0.0 + 3.141592653589793im # success
ऊपर के उदाहरण में log(n) को n की ऐसी वैल्यू चाहिए जो या तो धनात्मक वास्तविक हो, या कोई भी कॉम्प्लेक्स वैल्यू हो।
try ... catch ऋणात्मक वास्तविक वैल्यू की समस्याओं को पकड़ लेता है और गणित के संकेतन में सही कॉम्प्लेक्स उत्तर iπ लौटा देता है।
अगर आप उदाहरण के लिए कोई स्ट्रिंग आर्गुमेंट दे दें, तो यूज़र से उसे ठीक करने के लिए कहने के अलावा कोई चारा नहीं बचता।
अंत में, बाकी सब कुछ संभालने के लिए हमने rethrow() जोड़ा है, उन सबके लिए जो न DomainError हैं और न MethodError।
ध्यान दें: कभी-कभी try...catch ही आपकी ज़रूरत होता है, लेकिन इसका ज़रूरत से ज़्यादा इस्तेमाल न कीजिए।
अगर इसके बजाय if...else ब्लॉक इस्तेमाल किया जा सकता है, तो वह एक्सेप्शन पकड़ने से कहीं बेहतर परफॉर्मेंस देगा।
ध्यान रखिए कि ऊपर चर्चा किए गए error() फंक्शन को @error मैक्रो से भ्रमित नहीं करना चाहिए।
यह फंक्शन एक एक्सेप्शन पैदा करता है, जिसे पकड़ा न जाए तो वह कॉल स्टैक में ऊपर तक पहुँचता रहता है।
@error मैक्रो, अपने साथी @debug, @info और @warn के साथ, Logging मॉड्यूल का हिस्सा है और इसका उद्देश्य प्रोग्राम के प्रवाह को बदले बिना जानकारी देने वाले संदेश पैदा करना है।
आउटपुट डिफ़ॉल्ट रूप से टर्मिनल पर जाता है (गंभीरता के अनुसार रंग में), हालाँकि किसी वास्तविक ऐप्लिकेशन में और भी कई संभावनाएँ होती हैं।
julia> @warn "Something looks not quite right"
┌ Warning: Something looks not quite right
└ @ Main REPL[55]:1
julia> @error "Panic!"
┌ Error: Panic!
└ @ Main REPL[56]:1
try...catch वाले हिस्से में दिया गया पिछला उदाहरण भी देखिए।
एलेना एक अखबार कारखाने की नई क्वालिटी मैनेजर हैं। कंपनी में उनका आना अभी-अभी हुआ है, इसलिए उन्होंने तय किया है कि वह कारखाने की कुछ प्रक्रियाओं की समीक्षा करेंगी, ताकि देख सकें कि क्या बेहतर किया जा सकता है। उन्हें पता चला कि तकनीशियन बहुत सारी क्वालिटी जाँच हाथ से कर रहे हैं। उन्हें लगता है कि ऑटोमेशन का अच्छा मौका है, और वह आपसे, एक फ्रीलांस डेवलपर से, कहती हैं कि कुछ मशीनों की निगरानी करने वाला एक सॉफ्टवेयर बनाइए।
सबसे पहले आपको उत्पादन कमरे के आर्द्रता स्तर की निगरानी के लिए एक सॉफ्टवेयर लिखना है। कंपनी के सॉफ्टवेयर से पहले से एक सेंसर जुड़ा है, जो समय-समय पर कमरे का आर्द्रता प्रतिशत बताता है।
आपको सॉफ्टवेयर में एक फंक्शन बनाना है, जो आर्द्रता प्रतिशत बहुत ज़्यादा होने पर एक एरर फेंकेगा।
अगर आर्द्रता स्वीकार्य स्तर पर है, तो एक इन्फो लॉग जोड़ा जाएगा।
इस फंक्शन का नाम humiditycheck होना चाहिए और यह आर्द्रता प्रतिशत को आर्गुमेंट के रूप में लेना चाहिए।
अगर प्रतिशत 70% से अधिक हो, तो आपको ErrorException के साथ रुक जाना चाहिए (सटीक संदेश ज़रूरी नहीं है, लेकिन उसमें मापा गया आर्द्रता स्तर होना चाहिए)।
अन्यथा, "humidity level check passed: h%" संदेश के साथ एक इन्फो लॉग जोड़िए, जहाँ h आर्द्रता प्रतिशत है।
julia> humiditycheck(60)
[ Info: humidity level check passed: 60%
julia> humiditycheck(100)
ERROR: humidity check failed: 100%
एलेना आपके पहले काम से बहुत खुश हैं और आपसे मशीनों के तापमान की निगरानी करने के लिए कहती हैं। एक तकनीशियन ग्रेग से बातचीत के दौरान आपको पता चलता है कि अगर किसी मशीन का तापमान 500°C से अधिक हो जाए, तो तकनीशियन अधिक गर्म होने की चिंता करने लगते हैं।
मशीन में एक सेंसर लगा है जो उसका अंदरूनी तापमान मापता है। आपको पता होना चाहिए कि यह सेंसर बहुत संवेदनशील है और अक्सर खराब हो जाता है। ऐसी स्थिति में तकनीशियनों को इसे बदलना पड़ेगा।
आपको temperaturecheck नाम का एक फंक्शन बनाना है जो तापमान को आर्गुमेंट के रूप में लेता है। अगर सब ठीक है तो यह एक लॉग जोड़ता है, और अगर सेंसर खराब है या मशीन अधिक गर्म होने लगती है तो एरर फेंकता है।
चूँकि आगे चलकर आपको हर एरर पर अलग तरह से प्रतिक्रिया देनी होगी, इसलिए आपको इन दो तरह की एरर में फर्क करने का एक तरीका चाहिए।
nothing होगा।
इस स्थिति में आपको ArgumentError के साथ रुक जाना चाहिए (संदेश ज़रूरी नहीं है)।DomainError फेंकना चाहिए।"temperature check passed: t °C" संदेश के साथ एक इन्फो लॉग जोड़िए, जहाँ t तापमान है।julia> temperaturecheck(nothing)
ERROR: ArgumentError: sensor is broken
julia> temperaturecheck(800)
ERROR: DomainError with 800:
"overheating detected"
julia> temperaturecheck(500)
[ Info: temperature check passed: 500 °C
अगले काम के लिए आपको एक अधिक सामान्य, सब कुछ पकड़ लेने वाला एरर बनाना होगा।
इस बात के अलावा कि यह एक एरर है और इसका नाम MachineError है, इम्प्लीमेंटेशन के विवरण ज़रूरी नहीं हैं।
आप अपनी सुविधा के अनुसार फील्ड और संदेश शामिल कर सकते हैं।
अब जब आपकी मशीन एरर पकड़ सकती है और आपके पास एक कस्टम मशीन एरर है, तो आप एक रैपर फंक्शन जोड़ते हैं जो बता सकता है कि सब कुछ कैसे चल रहा है। पिछले फंक्शनों से मिले लॉग लौटाने के अलावा, इस रैपर को होने वाली किसी भी तरह की विफलता के आधार पर लॉग भी जोड़ने होंगे।
ErrorException फेंकती है, तो "humidity level check failed: h%" संदेश के साथ एक एरर लॉग जोड़ा जाना चाहिए, जहाँ h आर्द्रता प्रतिशत है।ArgumentError फेंकती है, तो "sensor is broken" संदेश के साथ एक वॉर्न लॉग जोड़ा जाना चाहिए।DomainError फेंकती है, तो "overheating detected: t °C" संदेश के साथ एक एरर लॉग जोड़ा जाना चाहिए, जहाँ t तापमान है।MachineError फेंका जाना चाहिए।humiditycheck और temperaturecheck के लॉग जोड़े जाएँगे।machinemonitor() नाम का एक फंक्शन बनाइए जो आर्द्रता और तापमान को आर्गुमेंट के रूप में लेता है।
julia> machinemonitor(42, 450)
[ Info: humidity level check passed: 42%
[ Info: temperature check passed: 450 °C
julia> machinemonitor(42, 550)
[ Info: humidity level check passed: 42%
┌ Error: overheating detected: 550 °C
└ @ Main # output truncated
Error: MachineError
julia> machinemonitor(82, 521)
┌ Error: humidity level check failed: 82%
└ @ Main # output truncated
┌ Error: overheating detected: 521 °C
└ @ Main # output truncated
Error: MachineError
julia> machinemonitor(42, nothing)
[ Info: humidity level check passed: 42%
┌ Warning: sensor is broken
└ @ Main # output truncated
Error: MachineError
Exercism पर साइन अप कीजिए और Julia को 35 कॉन्सेप्ट128 अभ्यास तथा असली इंसानों से मिलने वाली मेंटरिंग के साथ सीखिए और उसमें महारत हासिल कीजिए, वह भी बिल्कुल मुफ्त।