- Go भाषा में error handling की verbosity लंबे समय से users की top complaints में रही है
- विभिन्न syntax improvement proposals (जैसे check/handle, try, ? operator आदि) पर चर्चा और प्रयोग हुए, लेकिन community की पर्याप्त सहमति के बिना सभी खारिज कर दिए गए
- language changes का code, tools, docs आदि पर व्यापक प्रभाव और Go की सरलता बनाए रखने के सिद्धांत प्रमुख विचार बिंदु रहे
- मौजूदा तरीके की स्पष्टता, debugging में सुविधा और कुछ users की पसंद के कारण, syntax change लाने का औचित्य कमजोर है
- निकट भविष्य में error handling syntax बदलने की कोई योजना नहीं है, और संबंधित proposals बिना अतिरिक्त जांच के समाप्त किए जाएंगे
Go में error handling की verbosity का मुद्दा
- Go की पुरानी शिकायतों में से एक यह है कि error handling syntax बहुत ज़्यादा verbose है
- उदाहरण के तौर पर
if err != nil जैसा pattern code में बार-बार दिखाई देता है
- जिन programs में कई API calls की ज़रूरत होती है, उनमें यह syntax और भी ज़्यादा उभरकर आता है, और कई बार वास्तविक logic से अधिक error handling code हो जाता है
- वार्षिक user surveys में यह शिकायत लगातार ऊपरी स्थानों पर रही है
कम्युनिटी से चर्चा और शुरुआती प्रस्ताव
- Go team community feedback को महत्व देती रही है, इसलिए error handling improvements पर शोध जारी रहा
- 2018 की Go 2 project चर्चा में Russ Cox ने error handling समस्या के मूल बिंदु को औपचारिक रूप से संक्षेपित किया
- Marcel van Lohuizen द्वारा प्रस्तावित
check और handle mechanism शामिल था
- समान भाषाओं के साथ comparative analysis और कई alternatives की समीक्षा भी शामिल थी
- यह तरीका वास्तव में code को अधिक concise बनाता था, लेकिन complexity बढ़ने के कारण अपनाया नहीं गया
try proposal और उसके बाद
- 2019 में, कहीं अधिक सरल
try built-in function का proposal आया
check functionality को code में रखा गया, handle को हटा दिया गया
- इस proposal की control flow छिपाने के कारण आलोचना हुई और community backlash के बीच इसे वापस ले लिया गया
- इस अनुभव से पर्याप्त feedback के बिना तैयार proposal लाने के जोखिम का एहसास हुआ
- बड़े बदलावों के proposals के लिए शुरुआती design stage में अधिक व्यापक राय-संग्रह का महत्व स्पष्ट हुआ
अतिरिक्त प्रयास और विभिन्न proposals
- community से लगातार कई variants और alternative error handling approaches के proposals आते रहे
- Ian Lance Taylor के umbrella issue में स्थिति का सार संकलित किया गया, और Go Wiki व blogs आदि में उदाहरण इकट्ठा होते रहे
- 2024 में Rust से लिया गया
? operator लागू करने का proposal सामने आया
- छोटे usability tests में इसे intuitive बताया गया, लेकिन फिर भी विभिन्न रायों के बीच सहमति नहीं बन सकी
चर्चा में गतिरोध और निष्कर्ष
- आधिकारिक और अनौपचारिक proposals 3 से अधिक रहे, और community proposals सैकड़ों में थे, लेकिन पर्याप्त consensus की कमी के कारण सभी खारिज कर दिए गए
- Go के internal architect group के भीतर भी दिशा को लेकर मतैक्य नहीं है
- जब तक स्थिति में बदलाव या कोई विशेष consensus न बने, तब तक error handling syntax बदलने के प्रयास ही रोकने का निर्णय लिया गया है
मौजूदा तरीके को बनाए रखने के पक्ष में मुख्य तर्क
- अगर शुरुआती language design में syntactic sugar जोड़ा गया होता तो शायद विवाद न होता, लेकिन अब 15 साल से उपयोग में रहे तरीके का आदी ecosystem मौजूद है
- नया syntax लाने पर अनिवार्य रूप से पुराने और नए users के बीच code style gap और consistency टूटने की चिंता है
- यह Go की design philosophy (एक ही काम के कई तरीके न देना) और simplicity/consistency को महत्व देने के सिद्धांत से भी मेल खाता है
- short variable declaration (
:=) में redeclaration की अनुमति भी error handling के कारण आया एक द्वितीयक बदलाव है
- स्पष्ट error handling syntax (
if के माध्यम से) code पढ़ने, debugging, और breakpoints सेट करने में सहज लाभ देता है
- language change वास्तविक बदलाव के दायरे (code, docs, tools आदि) और लागत, दोनों के लिहाज से बड़ा बोझ है
वैकल्पिक सुधार और भविष्य की दिशा
- standard library की capabilities बढ़ाकर (जैसे
cmp.Or जोड़ना) कुछ repetitive code कम किया जा सकता है
- IDE और developer tools के code folding, autocomplete, LLM उपयोग आदि से व्यवहारिक कामकाज में verbosity को कुछ हद तक संभाला जा सकता है
- प्रमुख Go user groups (जैसे Google Cloud Next event attendees) में language change की ज़रूरत को लेकर नकारात्मक राय अधिक है
- Go का उपयोग बढ़ने के साथ verbosity की समस्या वास्तव में कम महसूस होती है
syntax improvement की ज़रूरत के समर्थन में तर्क
- user feedback के आधार पर अब भी error handling syntax सुधारने की मांग मौजूद है
- सिर्फ characters कम करने के बजाय, clarity बढ़ाने वाला error handling syntax code quality और safety सुधारने में योगदान दे सकता है
- केवल साधारण error checks नहीं, बल्कि वास्तविक भूमिका निभाने वाले error handling पर अधिक सूक्ष्म शोध की ज़रूरत है
अंतिम निष्कर्ष और आगे की नीति
- अब तक किसी खास consensus या वास्तविक बदलाव के अभाव को स्वीकार करते हुए, निकट भविष्य में error handling के लिए syntactic language changes पर सभी चर्चाएँ और proposals रोकने की घोषणा की गई है
- अब तक की discussions और research process ने अप्रत्यक्ष रूप से Go ecosystem और process improvements में योगदान दिया है
- भविष्य में यदि अधिक स्पष्ट problem definition और consensus बनता है, तो चर्चा फिर शुरू हो सकती है
- फिलहाल नए प्रयासों की बजाय Go की मजबूती और सरलता बनाए रखने पर ध्यान दिया जाएगा
1 टिप्पणियां
Hacker News राय
अगर कोई आसानी से यह सुझाव देना चाहता है कि Go टीम कोई और विकल्प चुन सकती थी, तो मैं चाहूँगा कि वह Go2ErrorHandlingFeedback wiki या GitHub issue search लिंक ज़रूर देखे। लगभग हर प्रस्तावित आइडिया पर पहले ही गंभीर चर्चा हो चुकी है, और Go टीम के पारदर्शी दृष्टिकोण के लिए आभारी एक उपयोगकर्ता के रूप में, मुझे हर दिन Go इस्तेमाल करने में खुशी मिलती है
draft design document में C++, Rust, Swift का ज़िक्र है, लेकिन मैं Haskell/Scala/OCaml जैसी functional languages की do-notation/for-comprehensions/monadic-let जैसी चीज़ें ढूँढ रहा था, जो मुश्किल से दिखती हैं। Go टीम भाषा-डिज़ाइन के उस्ताद जैसी लगती है, लेकिन आखिर में Java जैसी parametric polymorphism की कमी वाले static typing की सीमाओं से टकराकर error handling में हल नहीं दे पाती दिखती है। मुझे लगता है यह भाषा के बुनियादी डिज़ाइन से निकली समस्या है
समझदार और अनुभवी लोगों द्वारा लिखे गए दस्तावेज़ होने के बावजूद, यह बहुत अजीब है कि Haskell के Maybe/Either monad और bind operator (do-notation) जैसे समाधान कहीं भी उल्लेखित नहीं हैं। जबकि ये न तो वास्तव में कठिन हैं, न ही दुरूह, और errors को सुरक्षित तरीके से propagate करने का बहुत elegant और proven तरीका हैं। समझ नहीं आता कि Go community ने इसे क्यों नहीं अपनाया। इस पेज के अस्तित्व के लिए आभारी हूँ, लेकिन इतने प्रसिद्ध समाधान को छोड़ देना समझना मुश्किल है
लगभग हर भाषा कई बेहतर approaches देती है, तो सवाल उठता है कि सिर्फ Go में ही यह समस्या इतनी बड़ी क्यों दिखती है। क्या बस consensus नहीं बनता, या Go की कोई ऐसी विशेषता है जिसकी वजह से दूसरी भाषाओं के solutions फिट नहीं बैठते
Go की आलोचना में एक आम बात यह दिखती है कि अपेक्षाकृत कम विशेषज्ञ लोग मान लेते हैं कि Go developers को भाषा उनके मुकाबले कम समझ आती होगी। जबकि हक़ीक़त में ज़्यादातर मामलों में Go developers कहीं ज़्यादा अनुभवी और जानकार होते हैं। गैर-विशेषज्ञ अक्सर सोचते हैं कि ज़्यादा features वाली भाषा अपने-आप बेहतर होती है, लेकिन वे इस बात को नज़रअंदाज़ कर देते हैं कि असली महत्व पूरे संतुलन को ठीक रखने का है
मुझे लगता है कि नई language features जोड़ने में Go का सतर्क conservatism उपयोगकर्ताओं के लिए फ़ायदेमंद है। Swift के मामले में feature changes इतने ज़्यादा रहे हैं कि उसे सीखना भी मुश्किल है, और नए Mac पर भी कई बार एक साधारण project तक build नहीं होता। keywords लगातार बढ़ते और बदलते रहने की वजह से Swift में लंबे समय तक टिके रहना कठिन लगता है, जबकि Go की consistency उसकी बड़ी ताकत है
एक बार Go function में ऐसी असाधारण स्थिति थी जहाँ inner function से error आना अपेक्षित था, और अगर inner function error न दे तो उल्टा outer function को error return करना पड़ता था। इस असामान्य संरचना में
if err == nilसे branch करना था, लेकिन आदत से मैंनेif err != nilलिख दिया, और रोज़मर्रा के पैटर्न की आदत के कारण गलती पकड़ने में काफ़ी समय लगा। अगर अक्सर इस्तेमाल होने वालेif err != nilऔर कम इस्तेमाल होने वालेif err == nilके बीच language-level syntactic distinction होती, तो शायद ऐसी गलती कम होतीif err == nilलिखता हूँ, मैं// invertedजैसा comment डालता हूँ ताकि पैटर्न पर ज़ोर रहे। भाषा इसे अपने-आप संभाले तो बेहतर होगा, लेकिन अभी के लिए इस तरह distinction और स्पष्ट हो जाती हैif err == nil { return ... }पैटर्न कोड में और भी अजीब दिख सकता है। मौजूदा Go error handling साफ़ और पढ़ने में आसान है, इसलिए कई लोग इसे पसंद करते हैंif fruit != "Apple"जैसे पैटर्न में भी हो सकता है, इसलिए इसे मूलतः सिर्फ error handling की समस्या नहीं बल्कि सामान्य state branching की समस्या मानना चाहिए। error भी आखिरकार दूसरे state values की तरह ही handle होता हैif err != nilको किसी special symbol की तरह render करके उसे background में स्वाभाविक रूप से कम prominent दिखाया जा सकता है, और अलग तरह काif err == nilही उभरकर दिखे, ताकि editor स्तर पर गलती रोकने की संभावना बनेif err … {जैसे pattern को संक्षेप में दिखाकर readability बेहतर की जा सकती है, ऐसा भी एक सुझाव हैमुझे Go का explicit error handling तरीका पसंद है। मैं इसे बस ऐसे समझता हूँ कि function या तो हमेशा सफल होता है (minimal error) या fail हो सकता है। जो function fail हो सकता है, उसे अगले step पर जाने से पहले ज़रूर handle करना चाहिए। कई भाषाओं में exception handling की वजह से error stack पर ऊपर की ओर throw होता रहता है जब तक कोई catch न करे, जिससे अक्सर सिर्फ यह पता चलता है कि error कहाँ हुआ, पर ठोस hint कम मिलती है। Go में आपके पास साफ़ तौर पर ये options होते हैं: 1) error ignore करना 2) error होने पर तुरंत return करना 3) error wrap करके उपयोगी जानकारी जोड़ना 4) किसी specific error को interpret करके branch handle करना (जैसे 404 में बदलना)। Go2 में मैं
Result<Value, Failure>type या और अधिक specific तथा enumerable error types जोड़कर देखना चाहूँगा। Go 1 compatibility बनाए रखने के लिए इसे Go 2 में लाना ज़्यादा उचित लगता हैशुरू में Go का error handling तरीका मुझे पसंद नहीं था, लेकिन errors-are-values blog post पढ़ने के बाद और
panic(err)को सही जगहों पर इस्तेमाल करना शुरू करने पर, उल्टा बहुत संतोष मिलने लगा। ऐसी abnormal states जिन्हें parent code को सीधे handle नहीं करना चाहिए, वहाँ panic का उपयोग करके कोड की बिखरी हुई error branches काफ़ी कम की जा सकीं। इस तरह का error management असल काम में बहुत मददगार रहा है@operator से call site error suppression संभव है, और bash में-eजैसी error management techniques होती हैं, ऐसा उल्लेख हैtry/catch/finallyflow देखा था तो वह नया लगा, लेकिन अब उल्टा Go जैसी simple logic पसंद आने लगी है। code की अधिक मात्रा (Loc) के बावजूद, flow का स्पष्ट होना एक फ़ायदा लगता हैजब कहा जाता है कि असली error handling करने पर verbosity जल्दी छिप जाती है, तो यह सवाल उठता है कि manual stack trace बनाना क्या सच में ‘handling’ है? और Go की परिभाषा के हिसाब से फिर exception भी handling ही हुई, है न? ऐसा एक हल्का-फुल्का प्रतिवाद भी है
इस लेख में Go error handling की समस्या को सिर्फ “syntax verbose है” तक सीमित करना मुझे पसंद नहीं आया। मेरे हिसाब से असली समस्याएँ ये हैं: 1) errors का चुपचाप छूट जाना या गलती से ignore हो जाना आसान है 2) function result को value की तरह आसानी से pass या store नहीं किया जा सकता 3)
errors.Isजैसी nested error handling type system के साथ अटपटी तरह से जुड़ती है 4) error switching कठिन है 5) standard library में sentinel values का उपयोग बहुत है 6) generics के साथ तालमेल अच्छा नहीं, इसलिए packages की ज़रूरत पैदा होती हैElixir (और Erlang) में functions आम तौर पर
{:ok, result}या{:error, description}tuple return करती हैं। Elixir कीwithsyntax की वजह से error handling को block के नीचे एक साथ बाँधा जा सकता है, जिससे readability काफ़ी बेहतर होती है। अगर Go में भीwithstatement जैसा कुछ आ जाए, तो error nil होने पर ही execution आगे बढ़े और सबसे नीचे error handler block रखा जाए, इस तरह कोड और पढ़ने योग्य बन सकता हैसमझ नहीं आता कि Rust style को सीधे क्यों नहीं अपनाया जाता। खासकर अब जब generics आ चुके हैं, तो मिलता-जुलता implementation जल्दी संभव होना चाहिए। Rust का
?operator सुविधाजनक है, लेकिन यह तर्क कि वह errors को ignore करने को बढ़ावा देता है, समझ में नहीं आता। वास्तव में Go में error return values को ignore करने पर भी कई बार compiler error नहीं आता। Rust style की तरहResulttype return को मजबूरी बनाना ही गलतियों से बचा सकता है। अगर सुविधा के नाम पर विवाद है, तो फिर panic को भी प्रतिबंधित करना चाहिए, ऐसा कड़ा मत हैResultनहीं ला सकता क्योंकि उसमें sum type नहीं है, और हर type के लिए zero value चाहिए — यह उसका एक अजीब डिज़ाइन निर्णय है?operator” जैसी सुविधा के बारे में यह दावा कि इससे “wrapped errors का इस्तेमाल बंद हो जाएगा”, उसके जवाब में कहा गया कि ऐसे feature को wrapping को प्रोत्साहित करने वाले डिज़ाइन के साथ भी बनाया जा सकता हैमेरा मानना है कि Rust की तरह checklist बनाकर features अपनाने पर चर्चा नहीं होनी चाहिए; भाषा को उसकी समग्र consistency के भीतर डिज़ाइन करना चाहिए। सिर्फ feature list की सारी boxes tick हो जाने से कोई चीज़ तुरंत भाषा के स्वभाव के अनुरूप नहीं हो जाती