- Go 1.21 ने GODEBUG-आधारित compatibility को विस्तार दिया है, ताकि नया toolchain पुराने Go versions के व्यवहार को भी अधिकतम स्थिरता से लागू करे, और upgrade का बोझ कम हो
- Go ने 2012 में Go 1 से source compatibility का वादा किया है, और public API checks व बड़े पैमाने की internal testing के जरिए removal/changes से होने वाली टूट-फूट कम की है
time.Now की precision में सुधार, sort implementation में बदलाव, compress/flate output में बदलाव, strconv.ParseInt inputs का विस्तार, और net.ParseIP parsing में बदलाव जैसे documentation के हिसाब से allowed improvements भी मौजूदा programs को तोड़ सकते हैं
- Go 1.21 से compatibility के लिए GODEBUG settings कम से कम 2 साल या 4 Go releases तक रखी जाती हैं, और
go.mod के go version के आधार पर पुराना behavior default के रूप में preserve किया जा सकता है
- Go 2, Go 1 programs को तोड़ने वाली नई specification के रूप में नहीं आएगा; Go नई features जोड़ते हुए भी compatibility को प्राथमिकता देकर toolchain upgrades को स्थिर रखता है
Go 1 compatibility के बुनियादी सिद्धांत
- Go ने 2012 में Go 1 के साथ “Go 1 and the Future of Go Programs” document के जरिए यह लक्ष्य रखा कि Go 1 specification के अनुसार लिखे गए programs उस specification के जीवनकाल में बिना बदलाव के compile होते रहें और सही ढंग से चलते रहें
- इस वादे के केंद्र में source compatibility है
- नए Go version पर update करते समय code को फिर से compile करना होता है
- नए APIs जोड़े जा सकते हैं, लेकिन ऐसे additions से बचना चाहिए जो existing code को तोड़ दें
- किसी भी future change के लिए यह guarantee नहीं दी जा सकती कि वह सभी programs को कभी नहीं तोड़ेगा
- अगर कोई program किसी bug behavior पर निर्भर है, तो उस bug के fix होने पर program टूट सकता है
- Go breakage को जितना संभव हो उतना कम करते हुए stable upgrades बनाए रखना चाहता है
Public API checks से compatibility breaks रोकना
- Go development process में हर package की public API list को actual package से अलग files में maintain किया जाता है
- उदाहरण के लिए
go/api/go1.21.txt में bytes, cmp, context आदि के functions, methods और types की entries दर्ज हैं
- Standard tests यह verify करते हैं कि actual package API इन files से match करता है
- नया API जोड़ने पर उसे API file में भी जोड़ना होगा, तभी tests pass होंगे
- existing API बदलने या हटाने पर भी tests fail होंगे
- सिर्फ API removal ही नहीं, type change भी compatibility तोड़ सकता है
os.Stdout, *os.File type का global variable है
- इसे वही methods रखने वाले interface में बदलने पर
greet(f *os.File) जैसे * os.File की मांग करने वाले code टूट जाएंगे
- API checks, API changes/removals पकड़ने में उपयोगी हैं, लेकिन Go में हो सकने वाले सभी incompatible changes को नहीं रोकते
Tests जिनसे subtle breakage सामने आती है
- नए Go release के development version को Google के पूरे internal Go code पर लगातार test किया जाता है
- Tests pass होने पर वह commit Google के production Go toolchain के रूप में install होता है
- अगर internal tests टूटते हैं, तो माना जाता है कि external code भी टूट सकता है, और impact कम करने के तरीके खोजे जाते हैं
- अधिकतर मामलों में change को revert किया जाता है, या program को न तोड़ने के लिए फिर से लिखा जाता है
- कुछ changes programs को तोड़ सकते हैं, फिर भी वे महत्वपूर्ण और documentation के अनुसार compatible changes के रूप में बने रह सकते हैं
- ऐसे मामलों में भी impact scope कम किया जाता है और release notes में potential issues लिखे जाते हैं
Go 1.1 में सामने आए दो उदाहरण
-
Struct literals और नए fields
- Go 1 का
net.TCPAddr, IP और Port दो fields वाला struct था, और field names के बिना composite literals भी compile हो जाते थे
- Go 1.1 में
net.TCPAddr में Zone field जोड़ने पर existing code “too few initializers in struct literal” error के साथ compile नहीं हो पाया
- Compatible writing style है tagged literals का उपयोग करना
var myAddr = &net.TCPAddr{
IP: net.IPv4(18, 26, 4, 9),
Port: 80,
}
Zone specify न करने पर वह field zero value यानी empty string का उपयोग करता है
- Standard library structs के लिए tagged composite literals इस्तेमाल करने की requirement compatibility document में शामिल है, और
go vet बाद के versions के साथ compatibility के लिए जरूरी untagged literals की report करता है
-
Time precision
- Go 1 के बाद
time.Now को microsecond precision की जगह nanosecond precision return करने के लिए बदला गया
- यह change
time.Now value को save और load से round-trip करने के बाद equality expect करने वाले tests को तोड़ सकता था
- अगर stored representation सिर्फ microsecond precision preserve करता है, तो Go 1 में success लेकिन Go 1.1 में failure हो सकता था
- Go ने ऐसे tests को fix करने में मदद के लिए
Round और Truncate methods जोड़े, और release notes में potential issues व नए methods को document किया
- Better precision बेहतर behavior था और function की documented range के भीतर allowed था, इसलिए कुछ programs टूटने के बावजूद इसे release किया गया
Compatibility तोड़ सकने वाले तीन तरह के changes
-
Output changes
- Output change तब होता है जब function पहले से अलग output देता है, लेकिन नया output भी पुराने output जितना ही correct या उससे अधिक correct होता है
time.Now में nanosecond precision जोड़ना इसका प्रमुख उदाहरण है
- Go 1.6 में
sort implementation को लगभग 10% तेज किया गया, जिससे समान value माने जाने वाले elements का order बदल गया
- Go 1.5 output:
[red blue green white black yellow orange indigo violet]
- Go 1.6 output:
[red blue white green black orange yellow indigo violet]
- Sorting में equivalent results किसी भी order में return करना allowed है, लेकिन specific order expect करने वाले programs टूट गए
- Go 1.8 में
compress/flate को similar CPU और memory overhead के साथ छोटा output बनाने के लिए improve किया गया
- इसकी वजह से Google internal reproducible archive builds existing archives को हूबहू reproduce नहीं कर पाए
- उस project ने पुराने algorithm को बनाए रखने के लिए
compress/flate और compress/gzip को fork किया
- Output changes के लिए तैयार रहने का बेहतर तरीका है कि programs और tests सभी valid outputs accept करने के लिए लिखे जाएं
- अगर सचमुच reproducible output चाहिए, तो code fork किया जा सकता है, लेकिन फिर bug fixes से भी दूरी बन जाती है
-
Input changes
- Input change तब होता है जब function accepted inputs या processing method को बदलता है
- Go 1.13 ने numbers की readability के लिए underscore syntax जोड़ा, और
strconv.ParseInt भी इस नई syntax को accept करने लगा
- Underscore-separated numbers को अलग data format के रूप में इस्तेमाल करने वाले external user का code टूट गया
- वह code पहले
ParseInt try करता था और fail होने पर ही underscore handling करता था, लेकिन ParseInt अब fail नहीं होता था
net.ParseIP ने शुरुआती IP RFC examples के अनुसार leading zeros वाले decimal IP addresses accept किए थे
- Go ने
18.032.4.011 को 18.32.4.11 के रूप में पढ़ा
- BSD-family C libraries leading zero को octal की शुरुआत मानती हैं और उसी string को
18.26.4.9 के रूप में पढ़ती हैं
- Go 1.17 ने
net.ParseIP को leading zeros पूरी तरह reject करने के लिए बदला
- यह इसलिए चुना गया कि जब Go और C दोनों IP address parsing में सफल हों, तो उनका अर्थ समान हो
- Kubernetes को चिंता थी कि existing stored settings Go 1.17 में parse नहीं होंगी, इसलिए उसने original
net.ParseIP का fork इस्तेमाल करना शुरू किया
- User input के लिए बेहतर है कि values parse करने से पहले accepted syntax validate की जाए, लेकिन कुछ मामलों में code fork करना पड़ सकता है
-
Protocol changes
- Protocol change तब होता है जब package change बाहरी दुनिया से communication protocol में visible form में दिखाई देता है
- Go 1.6 ने automatic HTTP/2 support जोड़ा
- Go 1.5 clients सिर्फ HTTP/1.1 इस्तेमाल करते थे, इसलिए कुछ network middlebox environments में सही चल सकते थे
- Go 1.6 पर update करने पर HTTP/2 इस्तेमाल होने लगा, और उस environment में HTTP/2 काम न करने से program टूट सकता था
- Go modern protocols को default support देना चाहता है, लेकिन HTTP/2 enablement program या Go की गलती के बिना भी program तोड़ सकता है
- Go 1.6 ने release notes में change को document किया और HTTP/2 disable करने का तरीका दिया
TLSNextProto field को explicitly set करना
GODEBUG=http2client=0, GODEBUG=http2server=0, या दोनों साथ में set करना
- SHA1-based HTTPS certificates support भी protocol change का अधिक subtle उदाहरण है
- Certificate authorities ने 2015 में SHA1 certificates issue करना बंद कर दिया, और major browsers ने 2017 में इन्हें accept करना बंद कर दिया
- Go 1.18 ने SHA1 certificate support को default रूप से disable किया और GODEBUG से bypass की अनुमति दी
- कुछ Kubernetes installations private SHA1 certificates इस्तेमाल करती रहीं, इसलिए Go ने bypass setting को planned duration से ज्यादा समय तक बनाए रखने का फैसला किया
Go 1.21 में विस्तारित GODEBUG support
- Go 1.21 ने subtle compatibility issues भी कम करने के लिए GODEBUG usage को expand और formalize किया
- Go 1 compatibility rules के तहत allowed लेकिन existing programs को तोड़ सकने वाले changes के लिए, individual programs को नए behavior से opt out करने देने वाली GODEBUG setting define की जाती है
- कुछ मामलों में setting जोड़ना संभव नहीं हो सकता, लेकिन इसे बहुत rare case माना जाता है
- Compatibility के लिए GODEBUG settings कम से कम 2 साल, यानी 4 Go releases तक maintain की जाती हैं
http2client, http2server जैसी settings काफी लंबे समय तक, कुछ मामलों में indefinitely maintain रह सकती हैं
- जहां संभव हो, हर GODEBUG setting से
runtime/metrics counter जुड़ा होता है
- Counter name का format
/godebug/non-default-behavior/<name>:events है
- उदाहरण के लिए
GODEBUG=http2client=0 set होने पर /godebug/non-default-behavior/http2client:events HTTP/2 के बिना configured HTTP transports की संख्या गिनता है
- Program के GODEBUG defaults main package के
go.mod में लिखे Go version से match किए जाते हैं
- अगर
go.mod में go 1.20 है और Go 1.21 toolchain पर update किया जाता है, तो Go 1.21 में बदला GODEBUG-controlled behavior go.mod को go 1.21 में बदलने तक Go 1.20 behavior बनाए रखता है
- Individual GODEBUG settings को
package main की //go:debug line से बदला जा सकता है
- सभी GODEBUG settings central list में document हैं
panic(nil) का उदाहरण
- Go 1.21 में
panic(nil) अब non-nil runtime panic पैदा करता है
- इस change से
recover result भरोसेमंद तरीके से बता सकता है कि current goroutine panic में है या नहीं
- नया behavior GODEBUG setting से controlled है, और main package के
go.mod की go line पर निर्भर करता है
- अगर
go 1.20 या उससे नीचे है, तो panic(nil) अभी भी allowed रहता है
- अगर
go 1.21 या उससे ऊपर है, तो panic(nil) runtime.PanicNilError वाले panic में बदल जाता है
- Version-based default को
package main में निम्न line जोड़कर explicitly override किया जा सकता है
//go:debug panicnil=1
- यह combination नए toolchain पर update करते हुए भी पुराने toolchain का behavior preserve करने, सिर्फ जरूरी settings को fine-grained तरीके से control करने, और production monitoring से non-default behavior के use का पता लगाने में मदद करता है
- अधिक जानकारी “Go, Backwards Compatibility, and GODEBUG” में दी गई है
Go 2, Go 1 को नहीं तोड़ेगा
- “Go 1 and the Future of Go Programs” document में यह caveat शामिल था कि किसी दिन Go 2 specification आ सकती है
- उस अर्थ में Go 2 नहीं आएगा जो Go 1 programs को compile करना बंद कर दे
- 2017 में शुरू हुआ Go 1 का बड़ा revision, जिसे Go 2 कहा गया, पहले ही हो चुका है
- Go मानता है कि past से break करने की तुलना में compatibility कहीं अधिक मूल्यवान है, और उसने compatibility को और मजबूत करने की दिशा चुनी है
- आगे भी नए और दिलचस्प काम जारी रहेंगे, लेकिन toolchains के बीच upgrades को जितना संभव हो उतना stable रखने के लिए उन्हें सावधानीपूर्वक और compatible तरीके से आगे बढ़ाया जाएगा
1 टिप्पणियां
Hacker News की राय
compatibility में अहम सवाल “करना है या नहीं” नहीं, बल्कि “कैसे करना है” है। सच कहें तो यह past compatibility से ज़्यादा इस बात के करीब है कि अब से मेरा code बस चलता रहे
Go 1.21 दो ऐसी मुख्य चीज़ें देता है जो दूसरे language ecosystems में एक साथ कम ही दिखती हैं: हर बदलाव के लिए GODEBUG setting है, हर बदलाव को अलग-अलग वापस किया जा सकता है, और पुराने implementation के इस्तेमाल का पता लगाने वाले metrics भी हैं। साथ ही हर module के लिए toolchain version है, और पुराने Go तथा नए Go toolchain को modules की तरह सुरक्षित तरीके से अपने-आप fetch किया जा सकता है
बोनस के तौर पर, अगर
go 1.21.2जैसी कोई specific version दी जाए, तो नए Go पर चलाने पर भी, जब तक आप नए behavior को explicitly request नहीं करते, उससे जुड़ी opt-out configuration अपने-आप apply हो जाती है। इसे code,go.mod, environment variables—कहीं भी declare किया जा सकता है, इसलिए developers से लेकर deployers तक compatibility के लगभग सभी use cases को cover करने का यह सरल और सुंदर तरीका हैuse v5.24लिखने पर उसे Perl 5.24 की तरह behave कराया जा सकता है, और यह module level पर नहीं बल्कि file level पर apply होता हैसिर्फ़ यह तय करना कि नई version support करनी है या नहीं, अपने-आप में पहले से ही बेहद जटिल समस्या पैदा कर देता है, और फिर “हमें लगता है कि हम नई version support करते हैं और नई version भी हमें support करती है, लेकिन दोनों एक-दूसरे की कुछ चीज़ें miss कर रहे हैं” वाली गहरी खाई बन जाती है
यह दिशा सच में बहुत अच्छी है। Go codebase में जाकर यह उम्मीद कर पाना कि सिर्फ़ Go version बढ़ाने से सब कुछ ठीक चलेगा, इससे बेहतर क्या हो सकता है
हालांकि चिंता यह है कि type system को “यह गलत code है, इसलिए अब compile नहीं होगा” जैसी breaking changes के बिना बड़े स्तर पर improve करना मुश्किल है। Go team को इसमें दिलचस्पी है या नहीं, पता नहीं, लेकिन language features जोड़े बिना भी compile-time robustness को काफी बढ़ाने वाले कई low-hanging fruits हैं
उदाहरण के लिए unchecked
nilreporting, array access checks, nested struct literals की type inference, enum exhaustiveness checking जैसी चीज़ें। खासकर nested gRPC calls लिखते समय type inference का बस एक level चाहिए होता है, क्योंकि call की जा रही function signature में type पहले से मौजूद होता है, लेकिन Go में यह बहुत painful हैअगर Go type system सुधरता है, तो अच्छा होगा कि ऐसे सरल और सुंदर algebraic data types जोड़े जाएँ। वे Go में भी सच में अच्छी तरह fit होंगे, इसलिए खुद को यह gift दीजिए
पूरी तरह सहमत हूँ। Go releases का इंतज़ार इसलिए रहता है क्योंकि अक्सर उपयोगी चीज़ें जुड़ती हैं और कुछ भी टूटता नहीं
language का कोई भी हिस्सा इतना टूटा हुआ नहीं लगता कि उसे backward-compatible बदलाव से ठीक न किया जा सके। loop variable assignment जैसी कुछ गिनी-चुनी pitfalls के लिए भी आम तौर पर compatibility बनाए रखने वाले proposals हैं
निजी तौर पर मैं Go releases को लेकर उम्मीद वाले नज़रिए से सहमत हूँ, लेकिन दोनों ecosystems के attitude में फर्क दिलचस्प है
पहले झेली गई कुछ breakages का मैंने कभी सार लिखा था: https://news.ycombinator.com/item?id=29763324
Rust या gcc में compiler upgrade करते हुए language features मिलते हैं, लेकिन ज़्यादातर complex libraries वैसी ही रहती हैं और उन्हें अलग से upgrade किया जा सकता है। उदाहरण के लिए Rust में HTTP के लिए
hyperहै, C मेंlibcurl, यानी वे अलग हैंइसके विपरीत Go में compiler upgrade करते समय generics,
embed, toolchain features के साथ-साथtls, security libraries, HTTP client/server changes भी साथ आ जाते हैं।http,tls,cryptoजैसी बड़ी standard library chunks को अलग libraries होना चाहिए था; यह कहीं बेहतर होता। तब compiler को बिना डर upgrade किया जा सकता था, और libraries को अपनी गति से upgrade किया जा सकता थाasynckeyword introduce किया था, जबकि 2015 edition मेंasyncनाम की variable या function बनाई जा सकती थी, इसलिए यह breaking change थाbackward compatibility अच्छी चीज़ है, लेकिन यह पक्का कहना मुश्किल है कि Go compatibility तोड़ने से बचने के कारण भविष्य में कोई innovation X नहीं कर पाए, तो क्या वह ठीक होगा
मैं इस रुख का ज़ोरदार समर्थन करता/करती हूँ कि भविष्य का Go 2 कभी भी Go 1 compatibility को नहीं तोड़ेगा। अगर भाषा को इतना बड़ा बदलना ही पड़े, तो मेरे हिसाब से बेहतर होगा कि बस fork करके नाम बदल दिया जाए
हालांकि मैं सोचता/सोचती हूँ कि वे इससे आगे जाकर “Go 2 होगा ही नहीं” कहकर अस्पष्टता क्यों नहीं हटाते। अगर काल्पनिक Go 2 सभी Go 1 programs चलाता है, तो वह Go 1.xx release से किस मायने में अलग होगा। लेख कहता है कि “ऐसा Go 2 नहीं होगा जो Go 1 programs को तोड़े”, लेकिन लगता है उससे आगे नहीं कहता
https://github.com/golang/proposal/blob/d661ed19a203000b7c54...
इसमें बताया गया था कि अगर ऊपर की प्रक्रिया योजना के अनुसार काम करती है, तो एक महत्वपूर्ण अर्थ में Go 2 होगा ही नहीं, और नए language features और library features की ओर धीरे-धीरे transition होगा। किसी समय marketing के लिहाज़ से इसे “अब Go 2” कहा जा सकता है, लेकिन उसे skip भी किया जा सकता है। तर्क यह है कि जब C 2.0 नहीं था, तो Go 2.0 की ज़रूरत क्यों है
C, C++, Java जैसी लोकप्रिय भाषाएं भी असल में लगभग हमेशा 1.N version में ही रही हैं, और मुझे लगता है Go के लिए भी यही अपनाना बेहतर है। incompatible नई भाषा या core library के अर्थ में असली Go 2 users के लिए अच्छा विकल्प नहीं है और नुकसानदेह हो सकता है
आखिरकार मुझे लगता है कि वही तरीका समझ में आता है
अगर कोई नया language feature है जिसे community साफ़ तौर पर चाहती है, और उस feature को जोड़ने का सही तरीका या इकलौता तरीका नया keyword है, तो source compatibility कभी न तोड़ने के नियम की वजह से वह feature हमेशा के लिए नहीं जोड़ा जा सकेगा। भाषा की semantics बदलने वाले बड़े बदलावों से मैं सहमत हूँ, लेकिन backward-incompatible changes हमेशा बहुत बड़े बदलाव नहीं होते
सैद्धांतिक रूप से यह विचार अच्छा है कि backward compatibility कभी नहीं बदलेगी, लेकिन वास्तविकता में meaningful breaking changes भी होते हैं। पहली design के समय X या Y को ध्यान में न रख पाने वाले language feature को हमेशा ढोते रहना ज़रूरी नहीं कि फायदा ही लगे
मैं Go का बहुत इस्तेमाल करता/करती हूँ, और यह दिशा सच में दिल को सुकून देती है
compatibility भाषा team के लिए शायद बहुत मज़ेदार न हो। क्योंकि हमेशा एक पैर “दूर अतीत” में मजबूती से रखना पड़ता है। लेकिन बड़े Go systems maintain करने वाले के लिए यह सच में बहुत बड़ा तोहफ़ा है
अगर किसी चीज़ को सही तरह से fit नहीं किया जा सकता था, तो वह अभी सही नहीं थी, इसलिए दोबारा कोशिश की; और फिर भी fit न हो तो शायद हम problem को पर्याप्त रूप से समझ नहीं पाए थे, इसलिए उसे और लंबे समय तक mature होने देना सही था
ऐसे लोगों के साथ काम करना वाकई अच्छा था जो सावधानी से सोचते थे और सही ideas को अंदर लाने की कोशिश करते थे। Russ ने BDFL की भूमिका निभाई, Ian, Rob, और Rob के साथ काम करने का मौका मिला—इसके लिए आभारी हूँ, और इससे मैं कहीं बेहतर engineer बना/बनी
संबंधित लेख: Forward Compatibility and Toolchain Management in Go 1.21 - https://news.ycombinator.com/item?id=37122932
“boring अच्छा है। boring stable होता है। boring होने का मतलब है कि Go में क्या बदला, इसकी चिंता किए बिना आप अपने काम पर ध्यान दे सकते हैं” यह वाक्य सच में असर करता है
अपने मुख्य काम में मैं NodeJS और व्यापक JS ecosystem इस्तेमाल करता/करती हूँ, और परेशानी सच में बहुत है। ecosystem fragmented है और हर कोई अपने तरीके से करता है, इसलिए उसे stable बनाना मुश्किल है। फिर भी मुझे यह काम अब भी पसंद है, लेकिन अच्छा होगा अगर JS ecosystem में भी ऐसा stable modern foundation हो जिस पर भरोसा करके निर्भर किया जा सके
बहुत सारे tools और APIs Go में लिखे गए हैं, और target system पर अलग runtime की ज़रूरत नहीं होती—यह अक्सर बड़ा फायदा माना जाता है। भाषा भी सीखने और इस्तेमाल करने में सरल लगती है, VSC support और GoLand भी अच्छे हैं, और error handling जैसी आम शिकायतें भी निर्णायक खामी जैसी नहीं लगतीं
आने वाले दशकों तक development की mainstream बनने के लिए, या कम से कम job market का बड़ा हिस्सा बनने के लिए, Go को और क्या चाहिए, यह जानना चाहूँगा/चाहूँगी। क्योंकि कुछ जगहों पर इसे अब भी niche language माना जाता है
समस्या यह है कि सबको इस baseline तक कैसे लाया जाए। वहां तक पहुंच जाएं तो लगता है चीज़ें काफी बेहतर होंगी
साथ ही JS ecosystem में frontend UI work भी शामिल है, और उसके उपयोग के क्षेत्र इतने ज्यादा हैं कि कई implementations बनना टाला नहीं जा सकता। बल्कि यह वांछनीय भी है
Python से Golang में कुछ code ले जाना scale करने में बहुत मददगार रहा। यह देखकर सच में खुशी है कि Go अपनी core declaration यानी backward compatibility को लगातार निभाता रहेगा
IP parsing की बात है। हमेशा सोचता था कि असल में BSD का
inet_ntoaआखिर कैसे लिखा गया होगाatoi/atolऔर%d/%uइस्तेमाल करने वालाsscanfहमेशा ठीक-ठीक base-10 integer के रूप में parse करता है, इसलिए ऐसा अजीब effect पाने के लिए%iया 0-basedstrtouइस्तेमाल करना पड़ा होगाinet_atonmanual page में लिखा है कि यह 4.3BSD से आया है: https://github.com/dank101/4.3BSD-Reno/blob/master/lib/libc/...उससे पहले के 4.2BSD का
inet_addrभी वही logic इस्तेमाल करता है: https://github.com/dank101/4.2BSD/blob/master/lib/libc/inet/...inet_atonऔरinet_addraddress को सबसे natural तरीके से parse करते हैं।strtoulया खासकरsscanfजैसी चीज़ें इस्तेमाल करना awkward होता। C pointers की खूबसूरती यह है कि वे simple parsing tasks को बहुत आसान बना देते हैं, और शायद कुछ ज़्यादा ही आसान बना देते हैं/etc/hostsको “साफ़-सुथरा” करने के लिए मैंने हर octet को 0 से pad कर दिया थानतीजा यह हुआ कि वापस जाकर 0 हटाने पड़े
एक language designer के तौर पर, मैं यहाँ लिए गए फैसलों की इज़्ज़त करता हूँ, जिसमें असली Go 2 न बनाने का फैसला भी शामिल है
compatibility की guarantee देने के लिए मैं भी ये techniques अपनाने की सोच रहा हूँ