Zig comptime को उत्कृष्ट मानने का कारण
(scottredig.com)- Zig का compile-time (comptime) metaprogramming रनटाइम कोड की तरह पढ़ा जा सकता है, फिर भी यह struct field sum जैसे दोहराव वाले कोड के लिए हाथ से लिखे गए C function जितना efficient executable code बना सकता है
- अलग generic syntax के बजाय
comptime T: typeऔरanytypeका उपयोग करके generic programming करना, Zig comptime का एक मुख्य उपयोग है - runtime, comptime और build system — तीनों एक ही Zig भाषा साझा करते हैं, इसलिए Fizz Buzz जैसी function को compile के दौरान चलाकर पहले से गणना किया हुआ array बनाया जा सकता है
- compiler जहाँ संभव हो पहले ही evaluation कर देता है, और जिन हिस्सों में runtime values चाहिए केवल उन्हें बाद में machine code बनने वाले output bytecode के रूप में छोड़ता है
- Zig comptime text-based code generation जैसे कई काम कर सकता है, लेकिन C macro की तरह keywords को मनमाने ढंग से replace नहीं करता, इसलिए code reading और debugging का बोझ कम होता है
Zig comptime को पढ़ने का नज़रिया
- Zig का comptime metaprogramming feature है, लेकिन अंतिम behavior को पढ़ते समय compile time और runtime के अंतर को बहुत ज़्यादा सचेत होकर सोचने की ज़रूरत नहीं होती
zig zenकी तीसरी पंक्ति “Favor reading code over writing code” यहाँ एक महत्वपूर्ण मानदंड बनती है- macro या code-generation आधारित metaprogramming मूल code और expanded code की दो परतें बना सकती है
- इस तरह की अप्रत्यक्ष परतें code पढ़ना, debugging करना और behavior बदलना कठिन बना देती हैं
- array
[3]i64 = .{1,2,3}का sum निकालने वाले runtime code और structMyStructके fieldsa,b,cका sum करने वाले comptime code की तुलना साथ-साथ की गई हैinline for (comptime std.meta.fieldNames(MyStruct))से field names पर iterate किया जाता है@field(my_struct, field_name)से compile time पर ज्ञात field name का उपयोग करके field access किया जाता है
- struct field summation का उदाहरण runtime reflection जैसा दिख सकता है, लेकिन executable में उस struct type के लिए हाथ से लिखे गए sum function जैसा efficient code ही बचता है
- उदाहरण में दिखाया गया transformation, Zig implementation की सटीक पुनर्रचना नहीं बल्कि conceptual explanation के अधिक करीब है
- Zig core team ऐसे debugger पर काम कर रही है जो उदाहरण की तरह comptime और runtime के मिले-जुले code को step-by-step चला सके
Generics को comptime से संभालना
- Zig में अलग से कोई generic feature नहीं है
- किसी type को generic बनाना हो तो type लेने वाला function लिखकर उससे type return कराया जाता है
- उदाहरण:
pub fn GenericMyStruct(comptime T: type) type - returned
structके fieldsa,b,cसभीTtype का उपयोग करते हैं
- उदाहरण:
- generic function भी इसी तरह लिखे जा सकते हैं
- उदाहरण:
fn quadratic(comptime T: type, a: T, b: T, c: T, x: T) T quadratic(f32, ...)औरquadratic(i64, ...)की तरह type argument स्पष्ट रूप से दिया जा सकता है
- उदाहरण:
- अगर argument type function signature के दूसरे हिस्सों में महत्वपूर्ण न हो, तो special type
anytypeसे inference किया जा सकता है - केवल इसी तरीके से पूरे comptime को समझाया नहीं जा सकता, लेकिन Zig में आम generic tasks को समझने की यह अच्छी शुरुआत है
वही Zig code compile time पर चलाना
- Zig runtime, comptime और build system में एक ही भाषा का उपयोग करता है
- Fizz Buzz के उदाहरण में पहले
fizzBuzz(writer)function को सामान्य runtime output function की तरह लिखा जाता है1से100तक iterate किया जाता है3और5के multiples परfizzbuzz,3के multiples परfizz,5के multiples परbuzz, और बाकी पर संख्या output होती है
- उसी
fizzBuzzfunction कोcomptimeblock के भीतर चलाने पर पूरा output पहले से compute किया जा सकता हैstd.io.countingWriter(std.io.null_writer)से पहले ज़रूरी byte count निकाला जाता है- computed length से
buffer: [cw.bytes_written]u8array बनाया जाता है std.io.fixedBufferStream(&buffer)में दोबारा output लिखकरfull_fizzbuzzvalue बनाई जाती है
- अगर केवल मुख्य हिस्से को मापा जाए, तो precomputed version लगभग 9 गुना तेज़ चलता है
- उदाहरण छोटा होने के कारण कुल execution time पर दूसरे factors का असर ज़्यादा हो सकता है
- comptime और runtime में उपलब्ध values और features अलग होते हैं
comptime_int,comptime_float,typevalues केवल comptime में उपलब्ध होती हैं- कुछ functions केवल comptime arguments लेते हैं, इसलिए वे व्यवहार में comptime-only हो जाते हैं
- system calls या उन पर आधारित features केवल runtime में उपलब्ध होते हैं
- ऐसे विशेष features का उपयोग न करने वाला code comptime और runtime दोनों में एक जैसा चलता है
Partial evaluation के रूप में comptime को समझना
- comptime को compile प्रक्रिया के दौरान होने वाली partial evaluation के रूप में देखा जा सकता है
- partial evaluation वह तरीका है जिसमें function को कुछ arguments पहले से देकर, ज्ञात values पर निर्भर expressions को पहले substitute और evaluate किया जाता है, और अंत में अज्ञात arguments लेने वाला नया function बनता है
- array summation का उदाहरण evaluation process को चरणबद्ध ढंग से दिखाता है
forloop को हर iteration के अलग-अलग statements में तोड़ा जाता हैarray[0],array[1],array[2]को क्रमशः1,2,3से replace किया जाता हैsumको0 → 1 → 3 → 6की तरह update किया जाता है- अंत में यह
std.debug.print(..., .{6})जैसी form तक simplify हो जाता है
- struct field summation वाले उदाहरण को भी इसी तरह पढ़ा जा सकता है
inline forcomptime पर execute होता है, इसलिए यह fields"a","b","c"के लिए अलग-अलग statements में expand हो जाता है@field(my_struct, "a")बदलकरmy_struct.aबन जाता है- अंतिम function में सीधे
sum += my_struct.a,sum += my_struct.b,sum += my_struct.cजैसी lines होती हैं
- यह तरीका intent को सीधे code में व्यक्त करते हुए भी, field बदलने पर sum function को manually update करने वाली comment की ज़रूरत कम कर देता है
Compile-time evaluation और runtime code emission
- Zig comptime को compile-time evaluation और runtime code emission के संयोजन के रूप में भी देखा जा सकता है
- input code को compiler द्वारा execute किया जाता है
- जो statements compile time पर ज्ञात हैं, उन्हें तुरंत evaluate कर लिया जाता है
- जिन statements को runtime values चाहिए, उन्हें output code में जोड़ दिया जाता है
- यह नज़रिया Zig compiler के वास्तविक processing model के सबसे करीब है
- Zig पहले syntax parse करता है
- code को virtual machine के लिए bytecode में बदलता है
- VM जहाँ तक संभव हो evaluate करती है, और जहाँ runtime processing चाहिए वहाँ नया bytecode emit करती है
- यह नया bytecode बाद में machine code में बदलता है
ifजैसे conditionals जिनमें runtime input हो, उनके दोनों paths emit किए जाते हैं- dead code का semantic analysis नहीं किया जाता
- गलत function लिखे जाने पर भी, जब तक उसका वास्तविक उपयोग न हो, compile error नहीं आ सकता
- यह गुण compilation को अधिक efficient बनाता है और
#ifdefके बिना स्वाभाविक conditional compilation संभव करता है
- Zig में type names भी comptime पर evaluate होने वाले
typevalues के expressions हैं- function argument type जैसे सरल दिखने वाले type names भी comptime evaluation का परिणाम होते हैं
- यही गुण ऊपर दिए गए generic examples को संभव बनाता है
- ज़रूरत पड़ने पर अधिक जटिल expressions से भी type compute किया जा सकता है
- Zig का static analysis कई अन्य static type languages की तुलना में अधिक जटिल है
- सभी types जानने के लिए compiler के बड़े हिस्से को वास्तव में चलाना पड़ सकता है
- tools के पूरी तरह पकड़ बनाने तक, code completion जैसे editor features हमेशा अच्छी तरह काम नहीं करते
Text-based code generation से संबंध
- Zig comptime और text-based code generation का रूप अलग है, लेकिन वे समान तरह की समस्याएँ हल कर सकते हैं
- code-generation function
writeSumFn,writer.printसेsumFieldsfunction का source code output करती है- generator में चलने वाला code, Zig comptime वाले हिस्से के बराबर है
- generator से निकलने वाला code runtime code के बराबर है
- Zig का comptime version उसी logic को अधिक सीधे ढंग से व्यक्त करता है
std.meta.fieldNames(MyStruct)से field names मिलते हैंinline forऔर@fieldसे field access code बनाया जाता है
- type information को input के रूप में लेने वाला code generation, Zig में अधिक सरल हो जाता है
- text generation approach में type name और field name की जानकारी कहाँ से आएगी, यह अलग से हल करना पड़ता है
- Zig में type और field information को comptime पर सीधे handle किया जा सकता है
- अगर input बाहरी specification जैसा हो, तो
@embedFileसे file contents शामिल करके उसे सामान्य तरीके से parse किया जा सकता है - generic struct उदाहरण में comptime, text-based code generation की तुलना में type name references को अधिक सीधे तरीके से संभालता है
- text generation में
MyStruct_{s}जैसे नाम strings जोड़कर लगातार सही रखने पड़ते हैं - comptime में
GenericMyStruct(T)की तरह function को सीधे उपयोग किया जाता है
- text generation में
- कुछ अपवाद भी हैं
- ऐसे types बनाए जा सकते हैं जिनके field names comptime पर तय होते हैं
- इस स्थिति में field definitions की सूची वाली specification के साथ built-in function call करनी होती है
- ऐसे types में methods जैसी declarations define नहीं की जा सकतीं
- यह code expressiveness को सीमित नहीं करता, लेकिन दूसरे code के सामने expose किए जा सकने वाले API के रूप को सीमित करता है
- C जैसे text macros से संभव अधिकांश व्यावहारिक काम comptime से भी किए जा सकते हैं, लेकिन code का रूप लगभग पूरी तरह अलग हो सकता है
- Zig, text macro की तरह keywords को किसी दूसरे नाम से replace करने की सुविधा नहीं देता
आगे पढ़ने के लिए और standard library के उदाहरण
- Zig केवल comptime पर निर्भर भाषा नहीं है; अधिक जानकारी official website पर मिल सकती है
- language reference comptime की ठोस features को समझाती है
- Zig standard library में comptime उपयोग के उदाहरण मिलते हैं
std.debug.printद्वारा उपयोग किया जाने वाला format function एक शक्तिशाली generic function है- कई भाषाएँ format string को runtime पर parse करती हैं और early error detection के लिए अलग validator जोड़ सकती हैं
- Zig format string को comptime पर parse करके efficient output code बनाता है और सारी validation भी compile time पर करता है
ArrayListअपेक्षाकृत सरल लेकिन पूर्ण-featured generic container है- Zig का
mainfunction कई return types रख सकता है, और यह compiler magic नहीं बल्कि सामान्य comptime code से संभाला जाता है
1 टिप्पणियां
Hacker News की राय
compile-time programming में पहले से पहचानी जा चुकी समस्याओं की बिना आलोचना किए तारीफ करने के बजाय, काश इन्हें और गहराई से लिया जाता
staged programming नई नहीं है, और Lisp परिवार में भी दशकों से इसी तरह का काम होता रहा है, लेकिन उस प्रक्रिया में कई design trade-offs और समस्याएं सामने आई हैं। उदाहरण के लिए, इस तरह के generics parametricity को तोड़ देते हैं, जिससे सिर्फ function के type signature को देखकर अनुमान लगाना मुश्किल हो जाता है। Zig recursive generic types को कैसे संभालता है, यह भी अस्पष्ट है, और type checking तथा compile-time computation कब और किस क्रम में interact करते हैं, यह भी एक अहम design choice है। लेख कहता है कि compile-time code सिर्फ values ही नहीं, code भी generate कर सकता है, लेकिन hygiene पर बात नहीं करता। संबंधित चर्चा के लिए https://typesanitizer.com/blog/zig-generics.html अच्छा है
हालांकि दूसरी स्थितियों में Zig code में
comptimeदेखकर कभी-कभी “अ…” जैसा लगता है। Lisp macros की तरह, इसे ऐसी समस्याओं से बचने के लिए इस्तेमाल करना आसान है जो असल में होती ही नहींं, या code structure बेहतर बनाने पर गायब हो सकती हैं। मूल लेख में struct fields पर iterate करके values जोड़ने वाला उदाहरण असल में लोगों द्वाराcomptimeइस्तेमाल करने के तरीके का typical case है, लेकिन कई मामलों मेंstd.enums.EnumArrayजैसे वास्तव में iterable data structure का उपयोग करना बेहतर होता हैसैद्धांतिक तौर पर चिंता साफ है, लेकिन practical languages में यह कितना महत्वपूर्ण है, यह अलग सवाल है। C++ templates भी template specialization के जरिए parametricity तोड़ते हैं, लेकिन practice में यह आमतौर पर बड़ी समस्या नहीं बनता और उल्टा optimization को संभव बनाता है। उदाहरण के लिए
std::vector<bool>जैसी implementation, जिसमें हर element सचमुच 1 bit में store होता है, ऐसी flexibility होने पर ही संभव हैमुझे लगता है कि Zig-style
comptime, ज्यादा statically defined function signatures की तुलना में inferability बनाम expressiveness का सीधा trade-off है। यह केवल उस code को प्रभावित करता है जो types के जरिए ऐसी inference करता है, और जरूरत के हिसाब से चुना जा सकने वाला हिस्सा है। जब type signature काफी नहीं होता था, तब भी source की कुछ दर्जन lines पढ़ने पर usage आमतौर पर समझ आ जाती थी, और लंबे समय तक confusion नहीं रहा। recursive generic type example में declaration के दौरान उसी name का उपयोग करने पर “dependency loop detected” आता है, लेकिन workaround है, और लेख का generic example भी खुद को reference करता है। type checkingcomptimeके दौरान होती है; उदाहरण के लिए पहला@compileLog("Hi")execute होता है, लेकिन उसके बादconst a: u32 = "42";पर type error आने पर दूसरा log तक नहीं पहुंचता।comptimeऔर runtime के बीच type checking में subtle problems हो सकती हैं, लेकिन वे काफी मुश्किल code में ही दिखती हैं और आसानी से हल हो जाती हैं; core team को भी इनके बारे में पता है, इसलिए उम्मीद है कि 1.0 से पहले इन्हें address किया जाएगा। hygiene से आपका सटीक मतलब क्या है, इसके लिए और explanation चाहिएअगर function का logical purpose साफ हो और उसके name तथा parameter names अच्छे रखे गए हों, तो declaration से ही infer किया जा सकता है। parameter labels, type names वगैरह जैसे हिस्से जिन्हें programmer specify कर सकता है, उन्हें भी name का हिस्सा माना जा सकता है। linked article के title वाले conclusion से मैं सहमत हूं, लेकिन वह meaningful argument से ज्यादा points बटोरने वाली debate-team style writing जैसा लगता है। बेहतर framing flexibility बनाम complexity है। fixed generic system, अगर अच्छी तरह design किया गया हो, तो programmable system से सरल होता है लेकिन कम flexible होता है। Zig की खूबी यह है कि metaprogramming language लगभग सामान्य language जैसी ही है, और वह सामान्य language खुद भी simple है, जिससे extra complexity cost कम होती है। हालांकि compile-time code और runtime code मिल जाते हैं और clues कम होते हैं, इसलिए programmer के लिए यह अलग करना मुश्किल हो सकता है कि क्या कब execute हो रहा है। सोचता हूं कि language server या editor plugin
comptimecode को अलग background color देने वाला “comptime shader” दे तो कैसा रहेगाRust के अनुभव से, लोग const generics से जो कई चीजें करना चाहते हैं, वे
comptimeजैसी feature होने पर शायद आसान होंगी। parametricity बनाए रखते हुए const generics पर arithmetic allow करना implement करना कठिन है, और अगर वास्तव में चाहिए बस “output size N वाला hash function trait” जैसा कुछ है, तो उस उद्देश्य के लिए parametricity छोड़कर N से trait को पिछले code generation stage में बदल देना भी ठीक हो सकता है। लेकिन Rust macros उस तरह इस्तेमाल करने के लिए बहुत flexible और झंझट वाले हैं। फिर भी जिस क्षण parametric polymorphism को naive code generation feature से replace करते हैं, मुश्किलों का रास्ता खुल जाता हैD में यह 17 साल पहले से था। D की सुविधाएँ लगातार दूसरी languages में जाती रही हैं
Zig
comptimekeyword से उन blocks को mark करता है जो compile के दौरान execute होंगे, लेकिन D में execution keyword से नहीं, बल्कि इस बात से तय होता है कि expression constant expression है या नहीं। उदाहरण के लिएint s = sum(3, 4);runtime पर execute होता है औरenum e = sum(3, 4);compile time पर execute होता है। अगर non-constant globals, input/output, औरmalloc()जैसे system function calls से बचें, तो काफी functions बिना बदले compile time पर execute हो सकते हैं। D की automatic memory management की वजह से memory allocation भी संभव हैपहले static table बनाने के लिए अलग program लिखना पड़ता था, लेकिन compile-time function execution से अब इसकी जरूरत नहीं रही। array
tytabकी initial values एक lambda से आती हैं जो array calculate करके return करता है। पूरा example https://github.com/dlang/dmd/blob/master/compiler/src/dmd/ba... पर है। CTFE का एक और common use DSL बनाना हैअगर compiler जिस machine पर चल रहा है और program जिस machine पर चलेगा वे अलग हैं, तो D compiler correctness कैसे guarantee करता है? उदाहरण के लिए, compiler को कैसे पता कि
int s = sum(100000, 1000000)सभी x86 machines पर वही value देगा? CPU generations के बीच subtle differences हो सकते हैं; असल में host पर की गई calculation target machine पर भी वही result देगी, इसकी guarantee कैसे दी जाती है? या फिर मान लिया जाता है कि architecture same हो तो host और target पर्याप्त रूप से similar हैं?int sum(int a, int b) { return a + b; }रखकर_Static_assert(sum(3, 4) == 7, "look ma, check at compile time!");की तरह इस्तेमाल किया जा सकता है। समझ नहीं आता C standard इसे add क्यों नहीं करता, और यह अच्छी तरह काम करता हैcomptimecontext, दोनों में call कर सकता हैsquare(2)runtime call है औरcomptime square(3)compile-time call है। अगर कुछ compile-time compatible नहीं है तोcomptimecall compile error देता है, और मुझे यह एक अहम feature लगता है। क्योंकि जिस code के compile time पर execute होने की उम्मीद थी, वह input arguments बदलने की वजह से गलती से runtime evaluation में चला जाए तो यह warning signal बनता हैZig दिलचस्प लगता है, लेकिन काश इसमें operator overloading होती
operator overloading के खिलाफ ज्यादातर arguments ज्यादा convincing नहीं लगते। यह दावा कि अंदर असल में क्या हो रहा है पता नहीं चलता, पर्याप्त नहीं है, क्योंकि
addनाम का function भी multiplication करने के लिए बनाया जा सकता है। C++ केiostreamsयाboost::spiritअक्सर abuse cases के रूप में सामने आते हैं, लेकिन operator overloading वाली दूसरी languages में ऐसा ज्यादा नहीं दिखता और यह C++-specific समस्या लगती हैOCaml में operators को redefine किया जा सकता है, लेकिन केवल किसी दूसरे module के context के अंदर। उदाहरण के लिए अगर
Vec3module में+को redefine किया गया है, तोVec3.(a + b + c + d)याlet open Vec3 in a + b + c + dकी तरह लिखा जा सकता है। source पढ़ते समय “यह+कहाँ से आया?” जैसा सवाल नहीं रहता, और यहa.add(b).add(c).add(d)से कहीं बेहतर है। हालांकि Zig अब काफी stabilize हो रहा है, इसलिए ऐसी समस्या हल करने वाला बड़ा change आना मुश्किल लगता है__functions के पीछे कितनी magic चलती है, यह पता नहीं हो सकताZig का approach fresh है, और code follow कर पाने की क्षमता कुछ और characters type करने में लगने वाले कुछ seconds से ज्यादा महत्वपूर्ण है
ideal solution यह होगा कि language ऐसे user-defined operators दे जो साफ दिखाएँ कि वे overloaded हैं। उदाहरण के लिए
let c = a |+| bजैसे prefix/suffix form में code देखने वाला जान सकता है कि|+|operation असल में function call है। इसका misuse फिर भी हो सकता है, लेकिन मुख्य चिंताओं में से एक कम हो सकती हैअगर language shading languages की तरह vector math syntax सीधे provide करे तो अच्छा होगा। Zig में कम से कम Clang के Vector Extension से थोड़ा मिलता-जुलता
@Vector()type है, लेकिन दुर्भाग्य से यह Extended Vector Extension नहीं है। https://ziglang.org/documentation/master/#Vector और https://clang.llvm.org/docs/LanguageExtensions.html#vectors-... देखेंऐसी कोई proposal पहले से है या नहीं, मुझे ठीक से नहीं पता
fieldNamesNim केfieldPairsसे काफी मिलता-जुलता दिखता है, और बेहद convenient construct हैयह efficient serialization को बहुत आसान बनाता है, और हाल ही में मैंने
fieldPairsका इस्तेमाल करके किसी type के लिए thread-safety compile-time check लगभग 20 lines में implement किया। मुझे लगता है ऐसी feature programming languages की standard feature होनी चाहिए। Rust में जिन बातों की सबसे ज्यादा कमी लगती है, उनमें से एक यही है; और आखिरी बार जब मैंने try किया था, तब यह untyped macros तक सीमित था। यह बहुत restrictive है। बस उम्मीद करनी पड़ती है कि crate की struct परserdeimplement हो, और समान fields वाली struct को programmatically खुद बना भी नहीं सकतेकाफी अफसोस की बात है।
serdeजैसी चीजों को compile-time reflection हो तो implement करना कहीं आसान होताएकमात्र trade-off यह है कि ऐसी library को source code form में include करना पड़ेगा
कुछ हद तक पूरा C parser library लिखने के बाद, मुझे यह दावा ठीक से समझ नहीं आता कि भाषा में ही metaprogramming होना ज़रूरी है
अगर आप structs, serialization, properties, instrumentation आदि generate करना चाहते हैं, तो बस एक सामान्य C program लिखें जो source file को process करके source file output करे, और build script में उसे पहले चला दें। मुझे जिज्ञासा है कि लोग ऐसे meta programs को debug और test कैसे करते हैं। मेरा वाला तो सामान्य C program है, इसलिए बाकी code जैसे ही debugger और tools इस्तेमाल करता है
compiler खुद उसी भाषा में लिखा गया है, इसलिए आप ऐसा plugin लगा सकते हैं जो AST को read-only access करे और C# source emit करे। debugging के लिए अच्छा test framework बनाने में थोड़ा अतिरिक्त काम लगता है, लेकिन उसके बाद आप standard unit test framework के अंदर plugin लगे compiler को चला सकते हैं और interactive debugger में देख सकते हैं
“C में arbitrary compile-time execution:
cl /nologo /Zi metaprogram.c && metaprogram.exe,cl /nologo /Zi program.c। compile-time code native speed पर चलता है, debug किया जा सकता है, और पूरी तरह procedural व arbitrary होता है। compiler को code चलाने की ज़रूरत नहीं है।” https://x.com/ryanjfleury/status/1875824288487571873C में ऐसा करने के लिए source files process करने वाले C program के लिए पूरा C parser लिखना पड़ेगा
Python code generate करने वाला Python code लिखा, और फिर उसे दोबारा compile कराया। यह नाज़ुक और भयानक गड़बड़झाला था, और यही उन बड़े कारणों में से एक था जिनकी वजह से मुझे Python छोड़ना पड़ा। यह कुछ वैसा ही है जैसे पूछना कि क्या सभी function arguments को string के रूप में pass कर देना काफ़ी नहीं होगा। string-based code लिखने वाले लोग होते हैं, लेकिन यह दुर्लभ होना चाहिए, और भाषा को इससे बचने का तरीका देना चाहिए
एक दिलचस्प pattern यह है कि compile time पर structs generate किए जा सकते हैं
मैंने PyTorch में JSON file बनाकर, उसे Zig के
@embedFileसे पढ़कर, और किसी खासrunmethod वाले structs generate करके neural network implement करने का प्रयोग किया। सिद्धांततः इससे compiler neural network को सीधे optimize कर सकता है। बड़ा लाभ अभी साबित नहीं कर पाया, लेकिन एक बात यह भी है कि पूरा network stack पर रहता है, dynamic allocation नहीं होता। यह अच्छा है या नहीं, पक्का नहींcomptimeके बजाय Python में code generator लिखकर किया थायकीन नहीं कि
comptimeZig खास तौर पर तेज़ होगा, और मैं हर बार structs generate करने वाला JSON parser चलाना भी नहीं चाहतादिलचस्प तो है, लेकिन ऐसे मामलों में मैं “D ने पहले किया था” वाले comments से सहमत हो जाता हूँ
अगर Zig के
comptimeने आपको प्रभावित किया है, तो compile-time code evaluation और पूरे AST macro system वाले Nim को भी ज़रूर देखना चाहिएइसमें दूसरी niche languages जैसी ecosystem समस्याएँ हैं, और इसके साथ ही ध्रुवीकरण करने वाला maintainer, लंबे समय तक न टिकते दिखने वाले core contributors, और cryptocurrency company से मुख्य funding जैसे तत्व भी हैं। 10 साल पहले ये बातें परेशान नहीं करतीं, लेकिन अब स्थिति अलग है
लगता है Nim भी exceptions से दूर जाने की कोशिश कर रहा है, लेकिन exceptions functions को दूषित कर देते हैं और आपको उन पर ध्यान देने को मजबूर करते हैं, भले ही आप exception throw करने वाले functions का इस्तेमाल न करें[1]। अदृश्य control flow से निपटने के लिए ज़िंदगी बहुत छोटी है। [1]: https://github.com/status-im/nim-stew
Zig कुल मिलाकर काफ़ी अच्छी भाषा है और ज़रूरी काम करती है
अपने उद्देश्य से न भटकना बहुत ज़रूरी है, और इसी वजह से मुझे यह खास पसंद नहीं कि कुछ languages सिर्फ इसलिए हर जगह इस्तेमाल होने लगती हैं क्योंकि वे इस्तेमाल की जा रही हैं
काश Zig की metaprogramming क्षमता और Rust का विशाल ecosystem, community और safety जोड़कर कुछ मिलता
भाषा design के लिहाज़ से मुझे Rust से कहीं ज़्यादा Zig पसंद है, लेकिन एक अनाड़ी hobby programmer के रूप में, कम से कम अभी, मुझे भरोसा नहीं कि मैं Zig में वास्तव में उपयोगी या भरोसेमंद कुछ लिख पाऊँगा
क्योंकि compiler ऐसे issues को compile time पर पकड़ने में मदद नहीं कर रहा था। मुझे पता है Zig ऐसा वादा नहीं करता, लेकिन मेरे लिए यह निर्णायक कमी है, इसलिए लगता है Zig मेरे लिए सही भाषा नहीं है। दूसरी ओर
comptimeconcept मुझे Rust macros से बेहतर लगता है