30 पॉइंट द्वारा GN⁺ 2025-12-06 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • तीनों भाषाओं की दर्शन और मूल्य-प्रणाली के अंतर पर केंद्रित होकर, यह तुलना करती है कि हर भाषा किस समस्या को हल करना चाहती है
  • Go को ऐसी भाषा के रूप में समझाया गया है जो सरलता और स्थिरता को महत्व देती है, और फीचर्स को न्यूनतम रखकर सहयोग और maintenance को आसान बनाती है
  • Rust सुरक्षा और performance दोनों को साथ लेकर चलती है, और जटिल type system तथा trait संरचना के जरिए memory safety सुनिश्चित करती है
  • Zig को manual memory management और data-oriented design के माध्यम से डेवलपर को पूर्ण नियंत्रण देने वाली एक प्रयोगधर्मी भाषा के रूप में वर्णित किया गया है
  • तीनों भाषाओं के परस्पर विपरीत दृष्टिकोण यह दिखाते हैं कि programming language किन मूल्यों को लागू करती है, और डेवलपर किस दर्शन से सहमत है, यही चयन का आधार बनता है

भाषाओं की तुलना का दृष्टिकोण

  • लेखक अपने काम में इस्तेमाल होने वाली भाषा नहीं, बल्कि नई भाषाओं के प्रयोग के जरिए हर भाषा की मूल्य-प्रणाली को समझना चाहता है
  • केवल फीचर सूची की तुलना करने के बजाय, भाषा ने कौन-से trade-off चुने हैं, यह अधिक महत्वपूर्ण बताया गया है
  • Go, Rust, और Zig में कार्यात्मक रूप से काफी समानताएँ हैं, लेकिन डिज़ाइनर किन मूल्यों को प्राथमिकता देते हैं, यह अलग है
  • हर भाषा के दर्शन को समझकर यह आंका जा सकता है कि वह किस तरह के वातावरण और उद्देश्य के लिए उपयुक्त है

Go — सरलता और सहयोग पर केंद्रित भाषा

  • Go अपनी minimalism के कारण अलग दिखती है, और इसकी एक खासियत है कि “पूरी भाषा को दिमाग में रखा जा सकता है”
    • generics 12 साल बाद जोड़े गए, और tagged unions या error handling syntax sugar जैसे फीचर आज भी नहीं हैं
  • नए फीचर जोड़ने में बहुत सावधानी बरती जाती है, इसलिए boilerplate code अधिक है, लेकिन भाषा की स्थिरता और readability ऊँची रहती है
  • Go की slice, Rust के Vec<T> या Zig के ArrayList जैसी क्षमताओं को समेटती है, और memory location को runtime अपने-आप manage करता है
  • इसका डिज़ाइन C++ की जटिलता और compile delay को लेकर असंतोष से शुरू हुआ, और लक्ष्य था सरल और तेज compilation
  • यह enterprise वातावरण में सहयोग की दक्षता को महत्व देती है, और जटिल फीचर्स से अधिक स्पष्ट code और consistency को प्राथमिकता देती है

Rust — जटिल लेकिन शक्तिशाली सुरक्षा और performance

  • Rust “zero-cost abstractions” का दावा करती है, और कई तरह की अवधारणाओं को समेटने वाली maximalist language है
  • इसे सीखना कठिन इसलिए है क्योंकि इसकी concept density अधिक है, और इसमें जटिल type system तथा trait संरचना मौजूद है
  • Rust का मुख्य लक्ष्य performance और memory safety दोनों को साथ पाना है
    • UB(Undefined Behavior) को रोकने के लिए compile time पर सत्यापन किया जाता है
    • गलत pointer reference या double free जैसी स्थितियों से पैदा होने वाले अनुमान से बाहर behavior को रोका जाता है
  • ताकि compiler code के runtime behavior को समझ सके, डेवलपर को types और traits को स्पष्ट रूप से परिभाषित करना पड़ता है
  • इसी संरचना की वजह से दूसरों के code पर भरोसेमंदी बढ़ती है और library ecosystem सक्रिय बना रहता है

Zig — पूर्ण नियंत्रण और data-oriented design

  • Zig इन तीनों में सबसे नई भाषा है, अभी version 0.14 पर है, और standard library documentation लगभग नहीं के बराबर है
  • यह manual memory management अपनाती है, इसलिए डेवलपर को खुद alloc() कॉल करना होता है और allocator चुनना पड़ता है
  • Rust या Go के विपरीत, इसमें global variables बनाना आसान है, और runtime पर “illegal behavior” पकड़े जाने पर प्रोग्राम रोक दिया जाता है
    • build के समय चुने जा सकने वाले 4 release modes के जरिए performance और stability के बीच संतुलन किया जा सकता है
  • इसमें object-oriented programming(OOP) फीचर्स को जानबूझकर शामिल नहीं किया गया है
    • private fields या dynamic dispatch नहीं हैं, और std.mem.Allocator भी interface के रूप में implement नहीं किया गया है
    • इसके बजाय यह data-oriented design को लक्ष्य बनाती है
  • memory management में भी RAII शैली की सूक्ष्म object-level management के बजाय, बड़े memory blocks को समय-समय पर allocate और free करने वाली संरचना को प्रोत्साहित किया जाता है
  • Zig को स्वतंत्र और anti-establishment प्रवृत्ति वाली भाषा के रूप में चित्रित किया गया है, जो OOP सोच को हटाकर डेवलपर-नियंत्रित control को अधिकतम करती है
  • फिलहाल टीम सभी dependencies को फिर से लिखने के काम पर केंद्रित है, और stable version(1.0) अभी तय नहीं है

निष्कर्ष — भाषाएँ जिन मूल्यों को उजागर करती हैं

  • Go के केंद्र में सहयोग और सरलता, Rust के केंद्र में सुरक्षा और performance, और Zig के केंद्र में स्वतंत्रता और नियंत्रण हैं
  • तीनों भाषाओं का अंतर केवल फीचर्स का नहीं, बल्कि software development के प्रति दार्शनिक चयन का प्रतिबिंब है
  • डेवलपर अंततः इस आधार पर भाषा चुनता है कि वह किन मूल्यों से सहमत है

1 टिप्पणियां

 
GN⁺ 2025-12-06
Hacker News राय
  • Rust में mutable global variable बनाना मुश्किल नहीं है
    बस unsafe या synchronization देने वाले smart pointers का इस्तेमाल करना पड़ता है
    ऐसा इसलिए है क्योंकि Rust डिफ़ॉल्ट रूप से re-entrant है और compile time पर thread safety की गारंटी देता है
    अगर आपको static thread safety की परवाह नहीं है, तो इसे Zig या C की तरह आसानी से बनाया जा सकता है
    फ़र्क यह है कि Rust कोड के runtime behavior के बारे में ज़्यादा guarantee tools देता है

    • कई साल Rust इस्तेमाल करने के अनुभव से, मुझे लगता है mutable global variable “कर सकते हैं, इसलिए करना चाहिए” वाली चीज़ का एक典型 उदाहरण है
      दूसरी भाषाओं में लौटकर लोगों को इसे बेझिझक इस्तेमाल करते देखना safety के नज़रिए से पागलपन जैसा लगता है
    • “यह trivial है, बस ~ चाहिए” जैसी बातें मैंने C++, Perl, Haskell में भी सुनी हैं
      लेकिन इस तरह की “छोटी-छोटी” चीज़ें जुड़ते-जुड़ते बिल्कुल भी आसान नहीं रहतीं
      Rust इस सीमा को पहले ही पार कर चुका है, और अब यह बिल्कुल trivial नहीं है
    • मैं जानना चाहता हूँ कि क्या Rust compiler threads के बीच race condition को compile time पर पकड़ लेता है
      अगर ऐसा है, तो यह C की तुलना में काफ़ी आकर्षक लगता है
      यह भी जानना चाहूँगा कि जब दो variables को हमेशा साथ में lock करना पड़े, तब इसे कैसे handle किया जाता है
    • अगर मैं कोई language बनाता, तो mutable global variable को पूरी तरह ban कर देता
      debugging में आख़िरकार समस्या की जड़ वही निकलती है
  • Rust की conceptual density की आलोचना करने वाली बात पर, मेरा मानना है कि वास्तव में उसके सिर्फ 5% concepts जानकर भी आप productive रह सकते हैं
    12 साल से ज़्यादा समय से Rust इस्तेमाल कर रहा हूँ, लेकिन #[fundamental] जैसी चीज़ का मुझे कभी उपयोग नहीं पड़ा
    Rust में arena allocation भी किया जा सकता है, और allocator का concept भी मौजूद है
    एक default allocator होता है, और आमतौर पर Box::new जैसी explicit heap allocation का उपयोग होता है
    mutable global को static FOO: Mutex<T> = Mutex::new(...) की तरह बनाया जा सकता है, और memory safety के लिए mutex ज़रूरी है
    Rust का type system सिर्फ memory safety ही नहीं, बल्कि code की semantic safety सुनिश्चित करने के लिए भी डिज़ाइन किया गया है

    • लेकिन दूसरे developers अलग 5~10% concepts इस्तेमाल कर सकते हैं, इसलिए collaboration में आपको आख़िरकार और concepts सीखने पड़ते हैं
      C में इस तरह की complexity कम है
      complexity आख़िरकार एक महत्वपूर्ण मुद्दा है
    • “Rust में arena allocation हो सकता है” यह सही है, लेकिन ज़्यादातर Rust/Go code का default path छोटे-छोटे कई allocations पर आधारित होता है
      बात सिर्फ यह नहीं है कि कुछ संभव है या नहीं, बल्कि programming style के बुनियादी अंतर की है
    • अगर Rust में allocator एक type है, तो क्या m:n threading model में हर request को अलग arena दिया जा सकता है, यह जानने की जिज्ञासा है
    • यह भी सवाल है कि Rust का allocator global है या नहीं, और क्या सभी heap allocations एक ही allocator का उपयोग करते हैं
    • Casey Muratori का batch allocation वीडियो उल्लेख करते हुए कहा गया कि कुछ developers इसे ग़लत समझकर Rust के RAII की आलोचना करते हैं
      Zig Software Foundation ने Asahi Lina के Rust संबंधी बयान को ग़लत quote करने का उदाहरण भी दिया गया
      Zig का दूसरी languages को नीचा दिखाने वाला marketing attitude ज़्यादा पसंद नहीं आता
  • Zig पसंद आने का कारण यह है कि यह memory exhaustion को elegantly handle करने वाली language है
    इसमें माना जाता है कि हर allocation fail हो सकता है, और उसे explicitly handle करना पड़ता है
    stack space को भी जादुई चीज़ की तरह नहीं माना जाता, बल्कि compiler call graph का analysis करके maximum size infer करता है
    embedded environment में ऐसी resource-oriented design अनिवार्य है

    • लेकिन Linux जैसे overcommit इस्तेमाल करने वाले OS में व्यवहार में allocation failure होती ही नहीं
      इसे language level handling से हल नहीं किया जा सकता
    • अगर पूछा जाए कि Rust पहले से मौजूद होने पर Zig की ज़रूरत क्या है, तो मैं उल्टा पूछूँगा “C होते हुए Zig क्यों?”
      आख़िरकार दोनों manual memory management की समस्या से ही जूझ रहे हैं
      ऐसे में मुझे लगता है कि GC language इस्तेमाल करना ज़्यादा बेहतर है
    • recursion या function pointer calls होने पर Zig का stack size inference कैसे काम करता है, यह जानना दिलचस्प है
    • Zig पहला नहीं है; 1958 के JOVIAL के बाद की system language history को भी देखना चाहिए
    • Rust में भी pre-allocation अच्छी तरह की जा सकती है
      बस Rust standard library OOM पर panic करती है, इसलिए no-std environment में embedded development को सपोर्ट करने वाला अलग ecosystem मौजूद है
  • Go का slice Rust के Vec<T> जैसा नहीं है
    append() एक नया slice लौटाता है, जो पुरानी memory share भी कर सकता है और नहीं भी
    memory कम करने का कोई तरीका नहीं है, और अगर सिर्फ append(s, ...) लिखें तो नया slice नज़रअंदाज़ हो जाता है
    Go का रवैया है “मैंने जैसा कहा वैसा करो”, जबकि Rust का रवैया है “जाँचो कि जो कहा गया था वही हुआ या नहीं”
    यानी Go simplicity के लिए mistakes को allow करता है, और Rust complexity बढ़ने पर भी mistakes कम करने की दिशा चुनता है

    • व्यवहार में slices.Clip से memory कम की जा सकती है
      साथ ही सिर्फ append(s, ...) लिखने पर compile error आता है, इसलिए मूल टिप्पणी थोड़ी inaccurate है
      Go features जोड़ते समय complexity बढ़ने को लेकर काफ़ी सावधान रहने वाली language है
    • “append(s, …)” compile ही नहीं होता, इसलिए beginners ऐसी गलती कर ही नहीं सकते
    • Go में generics आने के बाद भी List[T] जैसे types का व्यापक उपयोग न होना दिलचस्प है
      शायद इसलिए कि growable list को सीधे पास करने की ज़रूरत अक्सर नहीं पड़ती
    • Go की spec और docs में ज़्यादातर foot guns साफ़-साफ़ लिखे हुए हैं
      अक्सर लोग docs नहीं पढ़ते और फिर हैरान होते हैं
  • C/C++ के UB(Undefined Behavior) को runtime checks से पकड़ना व्यवहारिक रूप से कठिन लगता है
    Android ने भी हर commit पर sanitizer लगाया, लेकिन Rust पर जाने के बाद ही exploits कम हुए

    • Android के sanitizer वाले दावे के लिए source माँगा गया
  • यह language comparison लेख अच्छा लगा क्योंकि इसमें हर language की strengths और weaknesses ईमानदारी से रखी गई थीं
    बस Raku का ज़िक्र न होना थोड़ा खला
    मेरी नज़र में अगर C–Zig–C++–Rust–Go low-level languages का एक continuum हैं, तो high-level तरफ Julia–R–Python–Lua–JS–PHP–Raku–WL जैसी कड़ी बनती है

    • WL क्या है, यह पूछा गया
    • Raku एक expressive general-purpose language है, जिसमें multi-dispatch, roles, gradual typing, lazy evaluation और powerful regex system built-in हैं
      language level पर grammar definition support होने से DSL या log parsing आसान हो जाती है
      VM आधारित होने से performance कम है, लेकिन problem structure को सीधे व्यक्त करने के लिए यह उपयुक्त है
      Perl के उत्तराधिकारी के रूप में यह flexible और consistent language बनने की दिशा में है
  • यह मानना ग़लत है कि Rust में function अगर pointer लौटाता है तो heap allocation अपने-आप हो जाती है
    local variables stack पर होते हैं और return के समय नष्ट हो जाते हैं, इसलिए pointer invalid हो जाता है
    Rust में safe mode में pointer dereference नहीं किया जा सकता, और unsafe mode में validity की गारंटी देने की ज़िम्मेदारी developer की होती है
    शायद Box::new को “implicit allocation” समझने की ग़लती हुई है

    • Go की escape analysis और Rust की explicit heap allocation को गड़बड़ाना समझना मुश्किल है
      यह या तो concept की ग़लत समझ है, या जानबूझकर mislead करने जैसा लगता है
  • Go की सबसे बड़ी ताकत उसका सरल concurrency model है
    goroutine की वजह से parallel code आसानी से लिखा जा सकता है

    • Go की एक और ताकत code consistency है, जिससे बड़े codebase में नेविगेट करना आसान हो जाता है
      interface implementations ढूँढना मुश्किल हो सकता है, लेकिन readability अच्छी होने से team collaboration में फ़ायदा मिलता है
    • Rob Pike की “Concurrency is not Parallelism” talk, Go की concurrency philosophy को अच्छी तरह समझाती है
      इसमें colored function नहीं हैं, और channel-based communication इतना सरल है कि सही concurrency code जल्दी लिखा जा सकता है
    • लेकिन मुझे लगता है कि Structured Concurrency इससे भी आसान model है
      संबंधित लेख: Structured Concurrency or Go Statement Considered Harmful
    • Zig का नया std.Io interface, Go के concurrency model से मिलता-जुलता है
      go keyword का समकक्ष std.Io.async, channels का std.Io.Queue, और select का std.Io.select है
    • Erlang developers शायद इस बात से सहमत नहीं होंगे कि Go का concurrency model सबसे आसान है
  • मुझे ऐसी language चाहिए जो Go की simplicity को Rust के result/error/enum handling और बेहतर generics के साथ जोड़े

    • मैं भी सहमत हूँ। GC होने के साथ मज़बूत type system वाली native language की market demand काफ़ी है
      OCaml, D, Swift, Nim, Crystal जैसी भाषाएँ देखी हैं, लेकिन अभी तक किसी ने बाज़ार पर कब्ज़ा नहीं किया है
    • सुना है कि आधुनिक OCaml में बहुत मज़बूत concurrency model है, और performance भी Go से टक्कर ले सकती है
    • Borgo language ने ऐसा प्रयास किया था, लेकिन वह रुक गया
      इसकी जगह Gleam को देखना बेहतर हो सकता है
    • Go का error proposal दिलचस्प लगा
      उम्मीद है कि इससे इस तरह की बार-बार आने वाली समस्याओं का हल निकलेगा
      generics अभी भी कठिन चुनौती बने रहेंगे
    • सबसे नज़दीकी विकल्प C# है, लेकिन वह अब भी OOP-केंद्रित language है
  • लेख का समग्र tone अच्छा लगा क्योंकि उसमें एक नए developer का उत्साह और जिज्ञासा महसूस होती है
    मेरा मानना है कि Go में generics की कमी सिर्फ minimalism नहीं थी, बल्कि trade-off पर गंभीर विचार का नतीजा थी
    Rust के lifetime बहुत से लोगों के लिए सबसे कठिन हिस्सा रहे, और language innovation अक्सर पुराने concepts के संयोजन से आती है
    Zig का manual memory management, OOP को हटाने से ज़्यादा Data-Oriented Design(DOD) दर्शन पर आधारित है
    संबंधित talk: Andrew का DOD प्रस्तुतीकरण

    • जैसा Russ Cox ने 2009 में “The Generic Dilemma” में पूछा था,
      असली सवाल था: “धीमा programmer, धीमा compiler, या धीमा execution — क्या चुनोगे?”
      लगता है Go team ने अंततः इसका एक संतोषजनक compromise खोज लिया