Go 1.22 रिलीज़
(go.dev)forलूप वेरिएबल अब हर iteration में नया बनाया जाता है, जिससे अनजाने shared bugs से बचा जा सके; integers परrangeभी अब संभव है- Compatibility Go 1 compatibility promise को बनाए रखती है, और उम्मीद है कि लगभग सभी Go programs पहले की तरह compile और run होंगे
- Workspace में
go work vendorसे बनाई गई vendor directory का उपयोग किया जा सकता है, और यदि workspacevendorमौजूद है तो-mod=vendordefault बन जाता है GO111MODULE=offवाले legacyGOPATHmode में module के बाहरgo getsupport हटा दिया गया है, लेकिनgo buildऔरgo testजैसे दूसरे build commands legacyGOPATHprograms में काम करते रहेंगे- Runtime अब heap objects के पास type-based GC metadata रखता है, जिससे Go programs की CPU performance में 1–3% सुधार होता है और कई programs का memory overhead लगभग 1% कम होता है
- कुछ object address alignment पहले के 16-byte या उससे अधिक की जगह 8-byte alignment में बदल सकते हैं; अधिक alignment मानकर लिखे गए assembly code को संशोधित करना होगा, और अस्थायी workaround
GOEXPERIMENT=noallocheadersउपलब्ध है - PGO builds अब अधिक calls को devirtualize कर सकते हैं, और representative Go programs के set में PGO enabled होने पर runtime performance 2–14% बेहतर होती है
- Standard library में पहला
v2packagemath/rand/v2जोड़ा गया है; इसमेंReadinherited नहीं है, globally shared generator हमेशा random seed लेता है,ChaCha8औरPCGsources हैं, और generic functionNदी गई है net/http.ServeMuxrouting patterns अब methods और wildcards को support करते हैं;{}वाले patterns और escaped paths के handling में छोटे backward-compatibility breaks हैं, औरGODEBUG=httpmuxgo121=1से पुराना behavior वापस लाया जा सकता हैcrypto/tlsserver का default minimum version अब, अगर explicitly set न हो, TLS 1.2 है; और pre-TLS 1.3 handshakes में ECDHE के बिना cipher suites अब default में उपलब्ध नहीं हैं- Execution tracer को पूरी तरह पुनर्निर्मित किया गया है: यह अधिकांश platforms पर OS clock का उपयोग करता है, streaming processing वाले split traces support करता है, full syscall duration दिखाता है, और यह भी बताता है कि goroutine किस OS thread पर चली
tracetool का web UI नए tracer support कार्य के हिस्से के रूप में अपडेट किया गया है, और Go 1.22 या बाद के version से बने programs के traces में thread-oriented view तथा full syscall duration display support जोड़ा गया हैvetने Go 1.22 loop variable semantics के अनुसार loop closure warnings को समायोजित किया है, और valuelessappend,deferके भीतर non-deferredtime.Since, तथाlog/slogkey/value mismatch के लिए नई warnings जोड़ी हैं- Bootstrap के लिए Go 1.20 का अंतिम point release या उससे नया version चाहिए; और उम्मीद है कि Go 1.24 को Go 1.22 के अंतिम point release या उससे नया version चाहिए होगा
darwin/amd64पर Go toolchain अब default रूप से PIE बनाता है; Go 1.22 macOS 10.15 Catalina पर चलने वाली आखिरी release है, और Go 1.23 के लिए macOS 11 Big Sur या नया version चाहिए होगाgo/typesमेंAliastype औरUnaliasfunction जोड़े गए हैं;gotypesalias=1में clients कोAliastype संभालना होगाslices.Delete,DeleteFunc,Compact,CompactFunc,Replaceअब shrunk segment के elements को zero करते हैं, औरInsertमें यदिirange से बाहर हो तो हमेशा panic होगा- Windows directory reading functions अब entries को batch में पढ़ते हैं, जिससे system calls कम होते हैं और performance अधिकतम 30% तक बेहतर होती है
1 टिप्पणियां
Hacker News की राय
पिछले 3 सालों में मैं मुख्यतः TypeScript इस्तेमाल कर रहा था, लेकिन हाल ही में Go इस्तेमाल करना शुरू किया। शुरुआत में arrays के लिए functions की कमी और कम flexible type system की वजह से थोड़ी चिंता थी
लेकिन जब मैंने 4~5 लोगों की टीम के लिए TypeScript project फिर से सेटअप किया, तो linting, server routing library चुनना, server चुनना, coding standards, basic error handling, nested
try/catchकी नरक जैसी स्थिति से बचने के लिए custom errors याResulttype लागू करना, testing और mocking, Prisma setup वगैरह में बहुत ज़्यादा समय लग गयामुझे TypeScript पसंद है, लेकिन बेहतरीन standard library, सही type safety, और built-in coding standards वाली भाषा इस्तेमाल करना सच में बहुत सुविधाजनक है। Go में भी कुछ quirks हैं, लेकिन वह काफ़ी अच्छा है, और routing का standard library में आ जाना भी अच्छा है क्योंकि अब एक चीज़ कम सोचनी पड़ती है। अब बस slices के लिए
map/filter/findfunctions का इंतज़ार हैTypeScript हर release के साथ power users के लिए और जटिल होता जा रहा है, जबकि Go
rangeover integers जैसी छूटी हुई चीज़ें जोड़कर इस्तेमाल को और सरल बनाता हैयह कुछ वैसा है जैसे game sequels settings और mechanics बढ़ाते-बढ़ाते नए users के लिए reset की ज़रूरत वाली स्थिति में पहुँच जाते हैं; programming languages में ऐसा करना कठिन होता है, इसलिए अच्छा है कि Go इस बात को ध्यान में रखता है
go:embedवgo:generateसे जो कुछ किया जा सकता है, वह दूसरे projects में देखते समय हर बार प्रभावित करता हैgolang.org/xpackages भी बहुत अच्छे हैं क्योंकि लगभग सभी internet RFC implementations तुरंत इस्तेमाल के लिए तैयार मिल जाते हैंmap/filter/findआने तक, lodash से प्रेरित lo library इस्तेमाल की जा सकती हैयह Go projects में मेरी पसंदीदा all-purpose utility है: https://github.com/samber/lo
आप कुछ करने के लिए documentation पढ़ते, और थोड़ी देर बाद कोई आपको documentation में न लिखा हुआ कोई काम का trick बता देता—ऐसा बार-बार हुआ
अगर official release notes थोड़े सूखे लगते हों, तो किसी ने उनका interactive version बनाया है: https://antonz.org/go-1-22
forloop variable sharing की समस्या पहले मुझे तुरंत समझ नहीं आई, लेकिन उसे खुद चलाकर अनपेक्षित परिणाम देखना मददगार रहाCompactऔरReplaceके examples भ्रमित करते हैं; पता नहीं यह सही है या नहींमैंने Go को 9 साल से अधिक इस्तेमाल किया है, और पिछले 4 सालों में Flutter की वजह से Dart भी बहुत इस्तेमाल किया है। मेरे हिसाब से दोनों भाषाओं का complexity के प्रति रवैया बिल्कुल उल्टा है। Dart हर संभव feature जोड़ना चाहती है, जबकि Go इसका उल्टा करती है
पहली बात, Dart में class के अंदर values initialize करने के बहुत ज़्यादा तरीके हैं, और इसी में बहुत समय चला जाता है।
final/const/static/lateprefixes के अनुसार constructor, factory, FlutterStatefulWidgetकाinitState()आदि में initialization की जगह बदलती रहती है, और refactoring करने पर initialization को बड़े पैमाने पर बदलना पड़ता है। variables जैसे दिखने वाले getter भी नए codebase में और भ्रम पैदा करते हैंदूसरी बात, Dart में maps, streams जैसी कई सुविधाएँ हैं जिन्हें एक ही line में ठूँसना आसान है, इसलिए समझने में मुश्किल one-liner code जल्दी बन जाता है। लेकिन debugging करते समय या जब junior developer
firstWhereOrNullजैसे hacks औरorElse: () => nullजैसे optional parameters से टकराते हैं, तो वे बहुत भ्रमित हो जाते हैं। कई बार उलझी हुई null safety या type errors काम रोक देते हैं, और जब इसे साधारण Go-styleforloop में बदल देते हैं, तो सच में राहत मिलती हैinitStateइस्तेमाल न करना बेहतर है। उदाहरण के लिए text field hint सेट करने जैसी मामूली चीज़ न हो तो इससे बचना चाहिएज़्यादातर Flutter pages या तो बहुत कम काम करते हैं, या parent
MyPageControllerobject बनाकर अपनी पसंद के अनुसार initialize करता है और child page उस controller के हिसाब से काम करता है। उदाहरण के लिए, list page में जब user किसी item को edit करना चाहता है, तो controller बनाकर item उसमें डालकर child page को भेज दिया जाता है; वापस आने के बाद parent controller के item, variables या callbacks देखकर तय कर सकता है कि UI में क्या बदलना हैइससे
InheritedWidgetजैसी चीज़ों को छुए बिना widgets के बीच interaction को बारीकी से नियंत्रित किया जा सकता है। बेशक इसे state management library के साथ इस्तेमाल करना अच्छा है, लेकिन व्यवहार में अक्सर लोग ऐसा नहीं भी करतेrangeभी ऐसा ही है—आख़िरकार टाइप किए जाने वाले characters की संख्याforEach(f)जैसी comprehension के बराबर ही होती है, बस वह तीन lines में फैला होने की वजह से लंबा दिखता है; खुद खोलकर लिखो तो कोई बड़ी बात नहींहालाँकि initialization के मामले में, काश Go में struct fields को किसी खास value से initialize करने का कोई idiomatic तरीका होता। constructor न होना ठीक है, लेकिन कभी-कभी मन करता है कि
booldefault रूप सेtrueinitialize होinitStateStatefulWidgetका override है और दूसरे frameworks के lifecycle events से अलग नहीं है; यह Flutter की अवधारणा है, इसलिए इसे constructor के साथ भ्रमित नहीं करना चाहिएसामान्य constructor और factory में क्या इस्तेमाल करना है, इसमें भ्रम हो सकता है, लेकिन सिर्फ
initStateकी वजह से Go को श्रेष्ठ कहना मुश्किल हैio.Copy,TCPConnसेUnixConnमें copy करते समय जहाँ संभव हो Linux काsplice(2)system call इस्तेमाल करेगा, और नया methodTCPConn.WriteToउपयोग में लाएगाinterface upgrade के ज़रिए एक बार फिर zero-copy I/O पारदर्शी रूप से बढ़ गया है।
iopackage में इस pattern से मिलने वाला फायदा सच में बड़ा हैफिर भी, यह अपेक्षित दायरे के भीतर ही है
बेहतर routing patterns इस समय एक अच्छा सुधार हैं, खासकर जब Gorilla Mux का भविष्य अनिश्चित दिख रहा है
हालांकि यह बदलाव छोटे स्तर पर backward compatibility तोड़ता है; कुछ हिस्से स्पष्ट हैं, जैसे
{और}वाले patterns का बदला हुआ व्यवहार, और कुछ कम स्पष्ट हैं, जैसे escaped paths की handling. इसेGODEBUGकेhttpmuxgo121फ़ील्ड से नियंत्रित किया जाता है, औरhttpmuxgo121=1सेट करने पर पुराना व्यवहार वापस पाया जा सकता हैलेकिन तब यह सवाल उठता है कि यह Go 1 compatibility promise से क्यों नहीं टकराता, जिसमें कहा गया है कि “Go 1 spec के अनुसार लिखा गया प्रोग्राम उस spec की पूरी उम्र तक बिना बदलाव compile होता रहेगा और सही चलेगा”
go.modकेgodirective के मान से बाँध दिया जाए1.22 या उससे ऊपर पर नया library behavior मिलता है, नहीं तो पुराना behavior. यह व्यवहार में कितना अच्छा काम करेगा, यह देखना होगा
{और}का उपयोग लगभग नहीं होतावे नए behavior को बंद करने का तरीका भी देते हैं, इसलिए code changes मजबूरन नहीं करने पड़ते, हालांकि नया environment variable सेट करना पड़ता है
इस रिलीज़ में
forloop semantics का बदलाव भी ऐसा ही उदाहरण है; यह भी व्यवहारिक रूप से breaking change है. फिर भी सभी Go programs compile और run होते रहते हैं, बस कुछ behavior थोड़ा बदल सकता है. Go ने एक practical approach चुना है, और शायद वही उसकी सफलता के कारणों में से एक हैgo.modके जरिए version के हिसाब से breaking changes करने ही हैं, तो कम से कम उन्हें बेहतर तरीके से break करना चाहिएजब
go.modको 1.22 पर बदलें, तब subtle runtime issues खोजने से कहीं बेहतर होगा कि code compile fail हो जाएGo 1.22 में loop की हर iteration अब एक नया variable बनाती है
इस पर पहले भी यहाँ चर्चा हुई थी: https://news.ycombinator.com/item?id=33160236 - Go: Redefining For Loop Variable Semantics (2022)
शायद मैं old-school हूँ, लेकिन functions पर
rangeजोड़ना मुझे पसंद नहीं है. इससे जितनी complexity language में जुड़ती है, उतनी सुविधा मुझे नहीं दिखती, और functional style, Go की explicit, imperative, और verbose लेकिन कम-featured style से मेल नहीं खाती. मुझे लगता है कि यही Go की बड़ी ताकतों में से एक थीइसी वजह से integers पर
rangeभी मुझे गलत दिशा लगती है. Go का lean feature set और कम cognitive load हमेशा उसकी बड़ी strengths और differentiators रहे हैंsoftware development की बड़ी समस्याओं में से एक यह है कि developers को बेवजह complexity जोड़ने या अपनी cleverness दिखाने से कैसे रोका जाए. खासकर शुरुआती करियर वाले developers अक्सर किसी समस्या को सीधे, कम elegant और अधिक verbose तरीके से हल करके आगे बढ़ने की बजाय, समाधान को जरूरत से ज्यादा complex बना देते हैं
अभी Go का generics support इतना परिष्कृत नहीं है कि यह उसे अच्छे से संभाल सके, इसलिए कुछ अजीब तरह की मजबूर सीमाएँ पैदा होती हैं
sql.Null[T]का जुड़ना अच्छा है. नए projects में मैं शायद इसका इस्तेमाल शुरू करूँगाअभी के काम में मैं sqlboiler के null [0] पर निर्भर हूँ, जिसका API काफी मिलता-जुलता है. यह
sql.Nullकी तरह काम करता है, लेकिन इसमें एक अतिरिक्तIsSet() boolmethod है, जो बताता है कि value को कभी explicitly set किया गया था या नहीं, जिससे “intentional null” और “uninitialized होने की वजह से null” में फर्क करने में मदद मिलती है. अच्छा लगता है, लेकिन मैंने इसे व्यवहार में कभी इस्तेमाल नहीं कियाstandard library mux को फिर से देखने और शायद chi हटाने की संभावना को लेकर उत्साहित हूँ. ऐसी functionality का standard library में आना सच में अच्छा है
ऐसी functionality के standard library में आने का मतलब है कि यह हमेशा maintain रहेगी, और बहुत से Go programs में एक जैसा approach इस्तेमाल होगा
अगर production में Go का इस्तेमाल करते हैं, तो क्या आप लोग जल्दी से latest version पर चले जाते हैं, या पुरानी releases पर अटके रहते हैं?
public projects को देखकर लगता है कि वे अक्सर comparatively नए features से बचते हैं. Generics न भी इस्तेमाल करें, तब भी मैं पुराने
interface{}की जगह Go 1.18 में आयाanyइस्तेमाल करना चाहूँगा, और मैंने यह भी सुना है कि बाद वाला ज़्यादा “idiomatic” हैइस बार थोड़ी उलझन हो गई, क्योंकि Go टीम ने हमारे default को 1.21 पर बढ़ाने से पहले ही 1.22 जारी कर दिया. अब इंतज़ार करना लगभग convention बन चुका है, और Go releases का कुछ तोड़ देना बहुत कम होता है
उदाहरण के लिए generics को वास्तव में इस्तेमाल करने से पहले मैंने लगभग 6 महीने इंतज़ार किया, ताकि उसकी usefulness, developer experience, और build/test speed पर असर देख सकूँ
लेकिन हम Go में end-user apps भी ship करते हैं, और वहाँ पुराने client OS के साथ compatibility के कारण 1.20 पर रहना पड़ता है. 1.21 में काफ़ी बड़ा cutoff था, इसलिए संभव है कि हम कुछ साल 1.20 पर ही रहें
latestcontainer से build और test चलाता है, और test suite काफ़ी मजबूत है, इसलिए व्यवहार में यह लगभग auto-update जैसा है. अगर कुछ मेल नहीं खाता, तो pipeline टूट जाती है, और तब तय करते हैं कि आख़िरी working version पर pin करना है या breaking change ठीक होने तक update टालना हैहर कुछ साल में एक बार नया version और third-party packages के बीच कोई subtle edge-case bug सामने आ सकता है, लेकिन परिभाषा के अनुसार ऐसे bugs test suite से बच निकलते हैं, इसलिए manual upgrade में भी शायद वे पकड़े नहीं जाते
अगर पुराने Go compilers का support चिंता का विषय है, तो पुरानी versions के लिए build conditions रखकर missing चीज़ें define की जा सकती हैं. उदाहरण के लिए,
// +build !go1.7के नीचेtype any = interface{}रखा जा सकता है