1 पॉइंट द्वारा GN⁺ 2025-06-04 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • 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 टिप्पणियां

 
GN⁺ 2025-06-04
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 और स्पष्ट हो जाती है
    • असल में यह syntax changes के खिलाफ़ तर्क है। अक्सर दिखने वाला if err == nil { return ... } पैटर्न कोड में और भी अजीब दिख सकता है। मौजूदा Go error handling साफ़ और पढ़ने में आसान है, इसलिए कई लोग इसे पसंद करते हैं
    • यही भ्रम if fruit != "Apple" जैसे पैटर्न में भी हो सकता है, इसलिए इसे मूलतः सिर्फ error handling की समस्या नहीं बल्कि सामान्य state branching की समस्या मानना चाहिए। error भी आखिरकार दूसरे state values की तरह ही handle होता है
    • IDE या font settings में if err != nil को किसी special symbol की तरह render करके उसे background में स्वाभाविक रूप से कम prominent दिखाया जा सकता है, और अलग तरह का if err == nil ही उभरकर दिखे, ताकि editor स्तर पर गलती रोकने की संभावना बने
    • 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 में लाना ज़्यादा उचित लगता है

    • अनुभव से लगता है कि error handling policy का फ़ैसला हमेशा caller को करना चाहिए, और नीचे के stack में उसे handle करना उचित नहीं। अंत में यह अक्सर errors को wrap करके ऊपर भेजने की एक साधारण दोहराव वाली प्रक्रिया बन जाती है
    • “Go की error handling” दरअसल JavaScript या Python नहीं, बल्कि functional languages, Rust, Java आदि अधिकांश भाषाएँ पहले से देती हैं। तर्क यह है कि सिर्फ generics हों तो Go शैली की error handling किसी भी भाषा में implement की जा सकती है। अगर तुलना JS या Python तक सीमित रहे, तो यह बस एक आम pattern है
    • “अगर function fail हो सकता है तो उसे ज़रूर handle करना चाहिए” यही Go की असली failure point है। Go में वास्तव में error को पूरी तरह ignore किया जा सकता है, इसलिए अगर robust software बनाना लक्ष्य हो, तो उल्टा Go का तरीका एक कमजोरी बन सकता है
    • Go2 शायद अंत में “कभी रिलीज़ न होने वाली प्रयोगशाला” बनकर रह जाएगा, ऐसी कड़वी राय भी है
  • शुरू में Go का error handling तरीका मुझे पसंद नहीं था, लेकिन errors-are-values blog post पढ़ने के बाद और panic(err) को सही जगहों पर इस्तेमाल करना शुरू करने पर, उल्टा बहुत संतोष मिलने लगा। ऐसी abnormal states जिन्हें parent code को सीधे handle नहीं करना चाहिए, वहाँ panic का उपयोग करके कोड की बिखरी हुई error branches काफ़ी कम की जा सकीं। इस तरह का error management असल काम में बहुत मददगार रहा है

    • इसका प्रतिवाद यह है कि इस तर्क से Go की कमज़ोर error handling का बचाव नहीं किया जा सकता, और सुधार होने पर भी उसके फायदे खत्म नहीं होंगे
    • PHP में भी level-based error handling या @ operator से call site error suppression संभव है, और bash में -e जैसी error management techniques होती हैं, ऐसा उल्लेख है
    • C# में जब पहली बार try/catch/finally flow देखा था तो वह नया लगा, लेकिन अब उल्टा Go जैसी simple logic पसंद आने लगी है। code की अधिक मात्रा (Loc) के बावजूद, flow का स्पष्ट होना एक फ़ायदा लगता है
    • यह भी उल्लेख है कि Rust का sum type आधारित error भी ‘errors are values’ paradigm के अंतर्गत आता है
  • जब कहा जाता है कि असली error handling करने पर verbosity जल्दी छिप जाती है, तो यह सवाल उठता है कि manual stack trace बनाना क्या सच में ‘handling’ है? और Go की परिभाषा के हिसाब से फिर exception भी handling ही हुई, है न? ऐसा एक हल्का-फुल्का प्रतिवाद भी है

    • दर्जनों lines की stack trace सच में कितनी स्पष्ट जानकारी देती है, इस पर संदेह है। व्यक्तिगत रूप से मुझे एक line का wrap error कहीं ज़्यादा प्रभावी लगता है, और log को साफ़ रखने में भी मदद करता है। 10 साल से ज़्यादा Go इस्तेमाल करने के दौरान मुझे runtime functions तक शामिल ऐसे verbose stack details की ज़रूरत कभी नहीं पड़ी
  • इस लेख में 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 की ज़रूरत पैदा होती है

    • Go के 90% professional programmers हर error return branch के लिए test cases लिखकर coverage पूरी करते हैं, जबकि exception-based languages में यह अनावश्यक काम है
    • यह कहना सही नहीं लगता कि इस लेख ने “It’s too verbose” को मुख्य समस्या बताया है। syntax बदलने से भी मूल सुधार सीमित रहेगा
    • यह दृष्टिकोण भी है कि Go की बहुत धीमी change velocity (generics में भी लंबा समय लगा) दरअसल एक strength है
    • एक Googler के रूप में, Go टीम के फ़ैसले से फिर निराशा हुई
  • Elixir (और Erlang) में functions आम तौर पर {:ok, result} या {:error, description} tuple return करती हैं। Elixir की with syntax की वजह से error handling को block के नीचे एक साथ बाँधा जा सकता है, जिससे readability काफ़ी बेहतर होती है। अगर Go में भी with statement जैसा कुछ आ जाए, तो error nil होने पर ही execution आगे बढ़े और सबसे नीचे error handler block रखा जाए, इस तरह कोड और पढ़ने योग्य बन सकता है

    • community consensus की समस्या के कारण Go में सबसे बुनियादी sum type, error handling, package management जैसी मूल्यवान features भी बहुत धीरे आती हैं। generics में 13 साल, error handling में 16 साल, package management में 9 साल लगे — बदलाव बेहद धीमा है। सावधानी ज़रूरी है, लेकिन perfection के पीछे भागते-भागते फ़ैसले हमेशा टलते रहते हैं, यह खलता है
    • Go का multiple return pattern कुछ नज़रियों से असामान्य माना जाता है। आलोचना यह है कि कई types return करने वाले function से असल में सिर्फ variable assignment ही किया जा सकता है
  • समझ नहीं आता कि Rust style को सीधे क्यों नहीं अपनाया जाता। खासकर अब जब generics आ चुके हैं, तो मिलता-जुलता implementation जल्दी संभव होना चाहिए। Rust का ? operator सुविधाजनक है, लेकिन यह तर्क कि वह errors को ignore करने को बढ़ावा देता है, समझ में नहीं आता। वास्तव में Go में error return values को ignore करने पर भी कई बार compiler error नहीं आता। Rust style की तरह Result type return को मजबूरी बनाना ही गलतियों से बचा सकता है। अगर सुविधा के नाम पर विवाद है, तो फिर panic को भी प्रतिबंधित करना चाहिए, ऐसा कड़ा मत है

    • राय यह है कि Go Result नहीं ला सकता क्योंकि उसमें sum type नहीं है, और हर type के लिए zero value चाहिए — यह उसका एक अजीब डिज़ाइन निर्णय है
    • ? operator” जैसी सुविधा के बारे में यह दावा कि इससे “wrapped errors का इस्तेमाल बंद हो जाएगा”, उसके जवाब में कहा गया कि ऐसे feature को wrapping को प्रोत्साहित करने वाले डिज़ाइन के साथ भी बनाया जा सकता है
    • सुविधा-प्रधान features (Rust style) की कमियों के रूप में यह बताया गया कि branch flow एक line में छिप जाता है, debugging breakpoints लगाना कठिन होता है, और यह enrich/handling से ज़्यादा bubbling पर केंद्रित होता है; इसी कारण Go ने कुछ syntax (जैसे ternary operator) नहीं अपनाए
    • Rust style की सीधी तुलना करें तब भी तकनीकी सवाल यह है कि Go में उसका actual equivalent क्या होगा, यह स्पष्ट नहीं है
    • generics आने के बाद Rust style जैसा क्या implement किया गया है, इसका code example देखने की जिज्ञासा भी जताई गई
  • मेरा मानना है कि Rust की तरह checklist बनाकर features अपनाने पर चर्चा नहीं होनी चाहिए; भाषा को उसकी समग्र consistency के भीतर डिज़ाइन करना चाहिए। सिर्फ feature list की सारी boxes tick हो जाने से कोई चीज़ तुरंत भाषा के स्वभाव के अनुरूप नहीं हो जाती

    • Rust के committee-style design के कारण उसकी syntax पढ़ने में कठिन और consistency में कमज़ोर लगने की छवि बनी है
    • “perfect solution” जैसी कोई चीज़ नहीं होती, ऐसा मत है
    • survey results के अनुसार Go की एकमात्र घातक समस्या error handling है, ऐसा कहना कठिन है; सिर्फ 13% ने ऐसा जवाब दिया, और मौजूदा स्थिति पसंद करने वाले users भी कम नहीं हैं। survey results देखें