Spinel - Ruby AOT नेटिव कंपाइलर
(github.com/matz)- Ruby सोर्स को पूरे प्रोग्राम के type inference के बाद C code में बदलकर standalone native binary जनरेट करने वाला AOT compiler
- Ruby के निर्माता matz द्वारा सीधे विकसित, और compiler backend खुद Ruby में लिखा गया है, इसलिए यह अपने आप को compile करने वाली self-hosting संरचना है
- miniruby(Ruby 4.1.0dev) की तुलना में लगभग 11.6 गुना तेज प्रदर्शन, Conway's Game of Life में 86.7 गुना, ackermann में 74.8 गुना, mandelbrot में 58.1 गुना गति सुधार
- Compile pipeline में Prism-आधारित parser पहले Ruby को AST text में बदलता है, फिर self-hosting backend type inference और C code generation करता है, और standard C compiler standalone binary बनाता है
- class, inheritance, block, exception handling, Fiber, built-in NFA Regexp engine, automatic promotion Bigint, pattern matching जैसे Ruby के व्यापक फीचर सपोर्ट
- 8 या उससे कम scalar field वाले छोटे class को value type के रूप में automatic stack allocation मिलता है, जिससे GC overhead पूरी तरह हट जाता है (10 लाख allocation 85ms → 2ms)
- string chaining
a + b + c + dको एक single malloc में flatten किया जाता है, और loop के अंदरsplitके लिए sp_StrArray को reuse करके अनावश्यक allocation हटाई जाती है - loop-invariant length hoisting, constant propagation, 3 स्टेटमेंट या उससे कम वाले method का automatic inline, repeated inference का early termination (~14% bootstrap time reduction) जैसी कई compile-time optimizations
- जनरेट की गई binary में runtime dependency शून्य, और यह सिर्फ libc + libm के साथ चल सकती है
eval, metaprogramming, Thread और Mutex आदि सपोर्ट नहीं हैं (सिर्फ Fiber सपोर्ट है)- MIT लाइसेंस
1 टिप्पणियां
Hacker News टिप्पणियाँ
अगर यह Matz ने बनाया है, तो उन्हें Ruby semantics की सीमाएँ भी अच्छी तरह पता होंगी, इसलिए इस पर भरोसा होता है
मेरा मास्टर्स थीसिस भी AOT JS compiler पर था, और वह चलता तो था, लेकिन input data पर इतनी पाबंदियाँ थीं कि आखिरकार छोड़ना पड़ा
उस समय JS developers खुद इस तरह की पाबंदियों का लगातार पालन करने के आदी नहीं थे, और
JSON.parseजैसी मूल रूप से unknowable input बड़ी बाधा थीअब TypeScript की वजह से यह तब की तुलना में कहीं ज़्यादा व्यावहारिक हो सकता है
सिर्फ सामान्य lambda calculus को देखें तो भी type inference की सीमाएँ साफ हैं, और Matt Might के papers या Shed-skin Python के काम में भी ऐसी ही पाबंदियाँ दिखती हैं
मुझे जिज्ञासा है कि असली Ruby code में
eval,send,method_missing,define_methodकितने आम हैं, और बिना type वाली parsing, जैसे JSON input, आम तौर पर कैसे संभाली जाती हैRuby parsing, translation से भी ज़्यादा कठिन है, इसलिए इसमें Prism इस्तेमाल किया गया है, और output C generate होता है
Ruby semantics का बेसिक हिस्सा अपने आप में इतना मुश्किल नहीं है
दूसरी तरफ मैं एक पुराने self-hosting AOT compiler पर काम कर रहा हूँ जो pure Ruby में लिखा है, और उसने अपना parser बनाने की ज़िद करके जानबूझकर कहीं ज़्यादा कठिन रास्ता चुना
शुरुआत के 80% में ही यह सीख लिया था कि मोटा-मोटी बनाकर भी काफ़ी Ruby code चलाया जा सकता है, और असल मुश्किल वाला "दूसरा 80%" उन चीज़ों में जमा है जिन्हें Matz ने इस प्रोजेक्ट और mruby से बाहर रखा है, जैसे encoding और तरह-तरह की peripheral सुविधाएँ
ईमानदारी से कहूँ तो Ruby में कई ऐसी सुविधाएँ भी हैं जिन्हें मैंने असली code में कभी नहीं देखा, इसलिए कुछ अगर deprecated भी हो जाएँ तो मुझे अजीब नहीं लगेगा
send,method_missing,define_methodबहुत आम हैंपाबंदियाँ mruby जैसी हैं, और उन पाबंदियों के भीतर भी इसके उपयोग मौजूद हैं
send,method_missing,define_methodका support देना अपेक्षाकृत आसान हैलेकिन eval() support करना बेहद दर्दनाक है
फिर भी Ruby में
eval()का बड़ा हिस्सा statically instance_eval के block version में घटाया जा सकता है, और ऐसे मामलों में AOT compilation काफ़ी आसान हो जाती हैउदाहरण के लिए, अगर
eval()में जाने वाली string को statically जाना या तोड़ा जा सके, तो समाधान की गुंजाइश बहुत बढ़ जाती हैअसल में
eval()का बहुत-सा उपयोग अनावश्यक होता है या सिर्फ साधारण introspection workaround जैसा होता है, इसलिए static analysis से संभाला जा सकता हैअगर मेरे compiler में वही bottleneck निकला, तो मैं वहीं से काम शुरू करूँगा
बिना type वाला JSON ingestion भी शायद इन्हीं mechanisms का इस्तेमाल करता होगा
इन्हें हटाने पर Crystal जितना strongly typed नहीं, लेकिन आधिकारिक Ruby जितना metaprogramming-निर्भर भी नहीं, ऐसी एक छोटी और पढ़ने में आसान भाषा बचती है
इसलिए इसमें काफ़ी potential दिखता है, लेकिन आखिरकार समय के साथ ही पता चलेगा
evalका अक्सर इस्तेमाल करने वालों में हूँइसके बिना काम चल सकता है, लेकिन मेरे लिए वह ज़्यादा ergonomic है
eval,exec,define_method, औरClass.new,Struct.newसे नई classes बनाने वाले patterns हैंइनका ज़्यादातर उपयोग app boot के समय या files require करते समय होता है, और एक अर्थ में वह पहले से ही compilation stage जैसा है
यह वही है जिसे Matz ने अभी RubyKaigi 2026 में पेश किया
यह experimental है, लेकिन Claude की मदद से लगभग एक महीने में बनाया गया, और live demo भी सफल रहा
इसका नाम Matz की नई बिल्ली के नाम पर रखा गया है, और उस बिल्ली का नाम Card Captor Sakura की बिल्ली के नाम से आया है, जहाँ वह Ruby नाम वाले character के साथ जोड़ी बनाती है
Matz जैसे व्यक्ति के लिए यह शायद 100x को 500x तक धकेलने जैसा हो सकता है
https://en.wikipedia.org/wiki/Spinel
लगता है वीडियो अभी live नहीं है, और शायद इस चैनल पर एक-एक करके आ रहे हैं
https://www.youtube.com/@rubykaigi4884/videos
प्रोजेक्ट का नाम भी कुछ भावनात्मक तरीके से रखा हुआ लगता है
यह निस्संदेह बेहद प्रभावशाली है, लेकिन AI agent के बिना maintain करना असंभव-सा लगता है
spinel_codegen.rb21 हज़ार lines का है, और कुछ methods में 15 स्तर तक nesting हैcompiler code का सुंदर होना वैसे भी मुश्किल है, लेकिन यह उस मानक से भी इंसानों के लिए maintain करना बहुत कठिन लगता है
compilers में subsystem boundaries साफ़ होती हैं और stages के बीच handoff भी स्पष्ट होता है, इसलिए वे उल्टा सबसे modular बन सकने वाली चीज़ों में आते हैं
समस्या आम तौर पर यह होती है कि पहले किसी तरह चला दिया जाता है और फिर refactor करने का समय नहीं मिलता, और तब गंदगी बढ़ती ही जाती है
spinel_codegen.rbतो लगभग eldritch horror स्तर का हैClaude के साथ मेरे यहाँ भी हमेशा ऐसा ही spaghetti code निकलता है, तो मुझे लगा मैं ही कुछ ग़लत कर रहा हूँ
लेकिन जिसे मैं top-tier programmer मानता हूँ, उसके इतने दिलचस्प प्रोजेक्ट में भी जगह-जगह code quality काफ़ी खराब दिखी, तो लगा समस्या सिर्फ मेरे साथ नहीं है
उदाहरण के लिए
infer_comparison_type()सबसे बुरा उदाहरण नहीं है, और पढ़ने में भी असंभव नहीं, लेकिन इसका कहीं ज़्यादा सरल और साफ़ implementation हो सकता था, फिर भी Claude वहाँ तक नहीं पहुँच पायाcomparison operators को
Setमें रखकरinclude?से संभालें तो वह छोटा, तेज़, ज़्यादा readable और maintainable होगालेकिन Claude हमेशा if-return chain की तरफ़ बह जाता है, और कभी-कभी तो लगता है जैसे if-else भी उसे अटपटा लगता है
मेरे Claude codebase में भी ऐसे patterns भरे पड़े हैं, और अब समझ आया कि यह सिर्फ मेरे यहाँ नहीं है
दूसरी तरफ़ बाकी files कहीं बेहतर हैं, खासकर
libdirectory, जो main Ruby repo कीextdirectory से मेल खाती लगती है और जिसकी quality ठीक हैAPI पर MRI Ruby का असर साफ़ दिखता है, और भले implementation काफ़ी अलग हो, Matz ने output को ज़्यादा व्यवस्थित बनाने के लिए शायद original API के कुछ हिस्सों जैसा रखने को कहा होगा
[1] https://github.com/matz/spinel/blob/98d1179670e4d6486bbd1547...
जब तक tests और benchmarks pass हो रहे हैं, मैं फ़िलहाल संतुष्ट हूँ
लेकिन यह अलग सवाल है कि इतनी बड़ी file AI के लिए भी आसान है या नहीं
मैं files को 300 lines के भीतर रखने की कोशिश करता हूँ, और मुझे लगता है कि जो code इंसानों के लिए समझना आसान है, वही coding agents के लिए भी आसान होगा
सीमाएँ ये बताई गई हैं
No eval:
eval,instance_eval,class_evalNo metaprogramming:
send,method_missing,define_method(dynamic)No threads:
Thread,Mutex(Fiber supported)No encoding: UTF-8/ASCII मानकर चलता है
No general lambda calculus:
[]call के साथ गहरी nested-> x { }UTF-8/ASCII वाला हिस्सा मुझे व्यक्तिगत रूप से बहुत बड़ी सीमा नहीं लगता, लेकिन बाकी बातें काफ़ी programs में सचमुच बाधा बनेंगी
और इन्हें वापस जोड़ने में भी काफ़ी काम लगता है
मैंने Ruby लंबे समय तक इस्तेमाल की है, और सूचीबद्ध सारी सुविधाएँ भी काम में ली हैं; उस नज़रिए से देखें तो विकास के बाद अब मुझे इसी तरह की सरल Ruby चाहिए
यह ज़्यादा सरल और समझने योग्य है, फिर भी Ruby की खास aesthetic बची रहती है
अब LLM की वजह से code generation productivity इतनी बढ़ गई है कि पहले जैसी metaprogramming से boilerplate घटाने की ज़रूरत कम हो गई है
क्योंकि developers द्वारा खुद code लिखने का अनुपात ही घट रहा है
syntax मिलता-जुलता है और उसमें static type system है, जिससे ज़्यादा efficient compiled code मिलता है
evalका न होना तो शायद बेहतर ही है, लेकिन threads और mutexes का भी न होना खलता हैdefine_methodकी अनुपस्थिति उसका उपयोग सोचकर समझ आती हैलेकिन
sendऔरmethod_missingमौजूदा libraries में आम हैं, और implementation भी compile time पर memory lookup table बनाकर उतनी मुश्किल नहीं लगतीइसलिए समझ नहीं आता कि इन्हें जानबूझकर छोड़ा गया है या बस अभी तक वहाँ पहुँचे नहीं हैं
मेरी उम्मीद दूसरी बात है, लेकिन कम-से-कम अभी compatibility के कारण production use मुश्किल लगेगा
बल्कि कम code पढ़ना था
यह सच में शानदार है, और मैं लंबे समय से Ruby के लिए AOT compiler का इंतज़ार कर रहा था
बस
evalया metaprogramming fallback का न होना अफ़सोस की बात है, हालांकि लगता है कि ऐसा छोटे high-performance subset पर ध्यान केंद्रित करने के लिए किया गया हैअच्छा होगा अगर इस AOT compiler से बने gem, MRI के साथ अच्छी तरह interact करें
standard Ruby और gems को package या bundle करने के लिए अभी भी tebako, kompo, ocran की ज़रूरत रहती है, और पहले ruby-packer, traveling ruby, jruby warbler जैसे projects भी थे
एक और विकल्प आना अच्छी बात है, लेकिन मैं बेहतर developer UX वाले अंतिम निर्णायक समाधान का इंतज़ार कर रहा हूँ
क्योंकि बहुत लंबे समय से उसका update नहीं आया था
मुझे समझ नहीं आता no threads क्यों
Ruby scheduler और नीचे का pthread implementation तो C layer में भी ठीक से काम करना चाहिए, इसलिए लगा शायद zero dependency की कोशिश होगी
अगर optional extension के रूप में बाद में जोड़ने की योजना नहीं है, या यह सिर्फ अभी तक नहीं हुआ, तो यह चुनाव थोड़ा अजीब लगता है
शायद बस अभी तक वहाँ पहुँचे नहीं हैं
multithreading को ठीक से बनाना वैसे भी बहुत कठिन होता है
यह जानकर हैरानी हुई कि इसे एक महीने से थोड़ा ज़्यादा समय में बना लिया गया
AI के बारे में कुछ भी कहें, कुशल developers के हाथ में यह गति में ज़बरदस्त बढ़ोतरी लाता है
और Matz बस
gem env|infoऔरfindसे काम चला लेते हैं, ऐसा लगता हैचूँकि इसे Matz ने बनाया है, इसलिए यह जानना दिलचस्प है कि भविष्य में इसके Ruby core का हिस्सा बनने की कितनी वास्तविक संभावना है
और अगर ऐसा हुआ तो Crystal के लिए यह कितना ख़तरा होगा
बड़े programs को compile और maintain करने के लिए ये विशेषताएँ लगभग अनिवार्य जैसी हैं
दूसरी ओर यह सीमित Ruby subset के लिए है, इसलिए ज़्यादातर लोकप्रिय Ruby gems इसमें वैसे के वैसे नहीं चलेंगे
C compilation की ओर उन्मुख language subset होने के लिहाज़ से यह PreScheme के ज़्यादा करीब लगता है
अभी के चरण में मुझे नहीं लगता कि दोनों सीधे एक ही क्षेत्र में प्रतिस्पर्धा कर रहे हैं
पूरी Ruby के लिए लगभग निश्चित रूप से JIT चाहिए होगा
[1]: https://prescheme.org/
यह कुछ-कुछ Rational Unified Process और Enterprise Architect जैसे tools की वापसी जैसा होगा
फ़र्क बस इतना होगा कि UML diagrams की जगह markdown files आएँगी
यह infrastructure tools के क्षेत्र में उपयोगी हो सकता है
मान लीजिए bundler Ruby में लिखा है लेकिन statically compiled है, और साथ में RVM जैसे Ruby installation tool की भूमिका भी निभा लेता है
मौजूदा Ruby buildpack Ruby में लिखा होने के बावजूद bootstrap के लिए bash की ज़रूरत रखता है, जो परेशान करता है और edge cases भी पैदा करता है
CNB ने उस समस्या से बचने के लिए Rust चुना, और बिना dependencies वाला single binary वितरित कर पाना सचमुच बहुत शक्तिशाली विचार है