- Lone Lisp एक ऐसा Lisp है जो
libcके बिना सीधे Linux system calls पर चलता है, और Matheus Moreira ने इसे यह परखने के लिए शुरू किया कि क्या सिर्फ freestanding C से एक पूरी language और user-space program बनाया जा सकता है - स्थिर Linux user-space ABI का सीधे इस्तेमाल करके उन्होंने
errno, locale, implicit file buffering जैसी C library की global state और legacy APIs को हटाया, और runtime, memory allocator, test tools खुद implement किए - FEXPR और proper tail-call optimization के साथ-साथ यह generators, delimited continuations, और resumable error handling को support करता है, और vectors, tables, continuations को भी उसी function-call style में handle करता है
- startup तेज़ है, लेकिन अस्थायी benchmarks में यह Python से 10~100 गुना धीमा list-level interpreter है; long term में C interpreter को bootstrap baseline के रूप में रखते हुए Lone के अंदर ही JIT compiler implement करने की योजना है
- Moreira code review और project management के लिए Claude का उपयोग करते हैं, लेकिन Lone का code खुद लिखते और review करते हैं, और पारंपरिक Linux user space को फिर से बनाने के लिए static site generator, shell, और utilities बनाना चाहते हैं
गेम्स से C++·Ruby·Lisp तक
- programming में रुचि की शुरुआत Mega Man Battle Network से हुई; उससे जुड़े forums पर बातचीत करने के लिए उन्होंने English सीखी और अपनी पहली language C++ भी सीखी
- Brazil के एक technical high school में 13~14 साल की उम्र के आसपास informatics course शुरू किया
- Dev-C++ और cplusplus.com tutorials का उपयोग किया
- 6 महीने में पूरा school curriculum सीख लिया और फिर दूसरे students की मदद करने के लिए teaching assistant के रूप में रखे गए
- game development भी आज़माया, लेकिन ज़रूरी physics knowledge की कमी के कारण सफल नहीं हो पाए
- C++ के बाद Java, Ruby, Python के रास्ते Lisp और Scheme तक पहुँचे, और Scheme की भाषाई सुंदरता से आकर्षित हुए
- Sun के Java tutorials लगभग पूरे पढ़कर object-oriented programming सीखी
- Java Swing और Nimbus design पसंद था, इसलिए math professor के लिए circle और arc draw करने वाला app भी बनाया
- Ruby में Git-style command-based argument parser Acclaim सहित gems लिखे
- कई languages को explore करने की प्रेरणा school projects से शुरू हुई, लेकिन बाद में जिज्ञासा और अपने लिए सही भाषा खोजने की इच्छा मुख्य कारण बन गई
Ruby की अभिव्यक्तिशीलता और C की पारदर्शिता
- Ruby में अक्सर method name अंदाज़े से भी सही निकल जाता था, और singular/plural व synonyms support होने के कारण यह उनकी सोच से अच्छी तरह मेल खाता था
items.each.with_index.mapजैसे shell pipeline-जैसे संयोजन से कम code में बहुत काम किया जा सकता है- आज भी वे Ruby हमेशा install करके रखते हैं और हाल में Rails project भी शुरू किया है
- C में function सीधे ELF symbols और assembly code से मेल खाते थे, इसलिए compiled output को समझना आसान था
- उनका मानना है कि modern C++ अब practically पहले वाली language नहीं रही, इसलिए वे अब यह नहीं कहते कि उन्हें C++ आता है
- Rust पर जाने की कोशिश की लेकिन टिक नहीं पाए; speed और ABI के कारण C में rewrite करने वाले Zig और उसके creator में भी रुचि रखते हैं
- किशोरावस्था में उन्होंने CRuby VM source पढ़ते हुए Stack Overflow के “Ruby ऐसा क्यों काम करता है” जैसे सवालों के जवाब implementation में ढूँढ़े
- बाद में CRuby, CPython, JVM, Guile, V8 का code देखा, और खास तौर पर Linux kernel source को professional C programming का मानक मानते हैं
दूसरों का code पढ़ने का तरीका
- वे सिर्फ library use करने पर नहीं रुकते, बल्कि internal implementation, drivers और hardware के communication, और छिपी हुई layers को समझने के लिए लगातार source पढ़ते हैं
- असली application बनाते-बनाते भी अक्सर underlying technology की खोज में भटक जाते थे, और पहले से हल की गई समस्याओं को बेहतर ढंग से फिर से बनाने की प्रवृत्ति भी विकसित हुई
- उन्हें लगा कि यह प्रवृत्ति सामान्य software development career से मेल नहीं खाती, इसलिए programming को पेशे के बजाय शौक के रूप में रखा
- शुरुआत से driver code समझ में नहीं आता था, लेकिन निराशा के बावजूद पढ़ते रहे और धीरे-धीरे कुछ behavior समझने लगे
RGB keyboard की reverse engineering
- Clevo barebone laptop के RGB keyboard control के लिए Windows app इतनी धीमी थी कि window खुलने में 1 मिनट से ज़्यादा लगता था, इसलिए उन्होंने खुद उसका replacement बनाया
- Wireshark से app द्वारा keyboard को भेजे जाने वाले USB packets capture किए, उनकी संरचना का विश्लेषण किया, और Linux user-space C driver लिखा
- GitHub पर डालने के बाद वे इसे भूल गए, लेकिन असली users सामने आए, और एक user ने GUI भी बनाया
- इसके बाद laptop की दूसरी सुविधाएँ, जैसे ACPI power management, भी reverse engineer कीं, हालांकि सभी features का पता नहीं चल पाया
libc को bypass करने वाला liblinux
- Linux system calls का code इतना सरल है कि वे लगभग साधारण function calls जैसे लगते हैं, इसलिए
libcके बिना भी सीधे Linux को target किया जा सकता है - Linux user-space ABI की stability के लिए जाना जाता है, लेकिन उनके अनुसार user-space components उतने स्थिर नहीं हैं
- manual में उन्हें ऐसे वाक्य मिले कि कुछ system calls को glibc support नहीं करता
getrandomको glibc में आने में लगभग 2 साल लगे, LWN का यह उदाहरण भी प्रभावी रहा
- सिर्फ system calls रखने वाली
liblinux.aबनाकर उसे-llinuxसे link करने के विचार से liblinux विकसित किया- यह freestanding C के लिए Linux system-call wrappers का संग्रह था
- C runtime (CRT) से उनका मतलब glibc, musl, uclibc जैसी standard C libraries से है
Freestanding C में गायब हो जाने वाली समस्याएँ
- Linux errors को साधारण return value की तरह लौटाता है, लेकिन C library उन्हें global variable
errnoमें रखती है libcहटाने से कई global states और पुराने APIs से भी बचा जा सकता हैerrno,rand/srand, locale state- reentrant न होने वाला
strtok - implicit file buffering, जो अनपेक्षित समस्याएँ पैदा कर सकता है
gets,atexit,signal,mallocmath.h, जो NaN औरerrnoके साथ मिलकर जटिल हो जाता है
- दूसरी ओर integer promotion rules और overflow checks की कमी, C की अपनी समस्याएँ हैं, इसलिए वे बनी रहती हैं
- overflow के लिए compiler built-ins का उपयोग करते हैं
- यह भी सावधानी रखते हैं कि कहीं वे खुद नई खामियाँ न बना दें
- standard library के बिना byte copy से लेकर integer→string conversion तक सब कुछ खुद लिखना पड़ा, लेकिन यह उनकी अपेक्षा जितना असंभव नहीं था
- glibc repository को समझना कठिन था, लेकिन
musl libcsource साफ़-सुथरा और explore करने में आसान था, इसलिए बहुत मदद मिली - C library और dynamic memory allocation के बिना, सिर्फ static memory का उपयोग करने वाला automated test suite भी Lone में implement किया
- glibc repository को समझना कठिन था, लेकिन
nolibc की खोज और Lone Lisp की शुरुआत
- उन्होंने Greg Kroah-Hartman से पूछा कि Linux के लिए कोई official C library क्यों नहीं है, और जवाब मिला कि पहले klibc project था
- बाद में पता चला कि Linux kernel developers ने internal tools के लिए nolibc.h बनाया है
- उन्हें लगा कि यह उनके liblinux से अधिक mature और usable है, इसलिए project को archive कर दिया
- आज
nolibc.hkernel tree के भीतर अस्थायीlibcजैसी directory तक बढ़ गया है, लेकिन external stability guarantee स्पष्ट नहीं है
- अगले project के रूप में Lone Lisp शुरू किया
- उनका मानना था कि अगर Linux पर सीधे चलने वाला freestanding Lisp बनाया जा सकता है, तो किसी भी program को उसी तरह लिखा जा सकता है
- यह modern Linux user space की जटिलता हटाकर स्थिर system-call binary interface के ऊपर से फिर शुरू करने का प्रयोग है
- Cosmopolitan को भी floating-point parsing implementation जैसी चीज़ों के लिए patches भेजे
- कई platforms के executable formats के रूप में एक साथ interpret होने वाले APE format और executable के अंदर embedded archive सुविधा की वे बहुत सराहना करते हैं
error handling और delimited continuations
- शुरुआती Lone में हर error path interpreter के भीतर
exit(255)पर खत्म होता था, लेकिन बाद में Common Lisp-style resumable condition system implement किया गया - error handling की बुनियाद delimited continuations हैं
- वे continuation को stack frame की copy और उसे दूसरी जगह replay करने के रूप में समझते हैं
- exception को भी वे ऐसे continuation का रूप मानते हैं जो value capture नहीं करता
- error types को
'not-foundजैसे symbols से lambda पर map किया जाता है- एक argument वाला
(lambda (error) ...)सामान्य exception handler की तरह काम करता है - दो arguments वाला
(lambda (error continuation) ...)continuation को call करके error वाले code को value के साथ resume कर सकता है
- एक argument वाला
- Common Lisp के
use-valueकी तरह signal करने वाला code restart options enumerate करे, ऐसा restart API जानबूझकर नहीं अपनाया गयाsignal,throw,transferको ऐसे बनाया गया है कि वे evaluator के भीतर के मूल mechanism के रूप में साधारण value return की तरह behave करें
FEXPR और callable language elements
- पारंपरिक Lisp evaluator जिस तरह
ifजैसे special forms को सीधे handle करता है, उससे भी बचा गया - Lone FEXPR support करता है, जो evaluator plugins के बराबर है और special forms को evaluator के बाहर ले जाता है
- इस design से pure Lisp functions में tail-call optimization पहले संभव हुआ, लेकिन primitives में कुछ समय तक bugs रहे
- primitive को tail position में return करने देने के लिए अलग mechanism जोड़कर इसे ठीक किया गया
- vectors और tables भी callable हैं
([1 2 3] 0)1लौटाता है([1 2 3] 0 4)vector को[4 2 3]में बदल देता है
- continuations और generators भी वही calling convention follow करते हैं
controlcontinuation-supportingbeginजैसा हैtransferसबसे निकट केcontrolblock से बाहर निकलता है और interruption point को दर्शाने वाला callable continuation लौटाता है- उस continuation को किसी value के साथ call करने पर रुकी हुई computation अलग return value के साथ resume होती है
system calls और execution structure
- Lone शुरू होने से पहले parent process
execvecall करता है, और Lone internal memory management के लिए लगभग 12 बारmmapकरता है - यह standard input से script पढ़कर चलाता है और फिर exit करता है; execution के दौरान
mmap,munmap,mremapअतिरिक्त रूप से हो सकते हैं - module system
openatऔरcloseका उपयोग करता है - Linux के 300+ system calls में से खुद सिर्फ कुछ का उपयोग करता है, लेकिन Lisp level पर system-call primitive देता है ताकि programs बाकी calls भी कर सकें
ioctlजैसे calls, जिनमें kernel C structs चाहिए, उनके लिए struct creation/manipulation feature जोड़ना होगा- terminal size query भी ऐसा ही एक उदाहरण है
Lone से बनाना चाहने वाला user space
- language level पर error handling, proper tail-call optimization, generators, delimited continuations implement हो चुके हैं, और long term में Erlang/BEAM के ideas भी लाने की योजना है
- structure को इस तरह तैयार किया जा रहा है कि कई interpreters parallel में Lisp code चला सकें
- Lone से बनाया जाने वाला पहला program उनके मौजूदा PugJS fork-based static site generator का replacement है
- उसके बाद अपना shell और utilities लिखकर पारंपरिक Linux user space को अपनी तरह फिर से बनाने की योजना है
envको Lone Lisp table में export करने वाला implementation भी बनाया है; उस समय iteration feature नहीं था, लेकिन अब generators support हैं- interpreter में special ELF segment से Lisp code पढ़कर execute करने की सुविधा भी है
- interpreter binary की copy बनाकर उसमें Lisp code inject किया जाए तो standalone executable बनाया जा सकता है
Claude के साथ review और project management
- कुल काम की मात्रा पर कोई सीमा नहीं है, लेकिन उनका मानना है कि language की feature set अब काफ़ी हद तक पूर्णता के करीब है
- वे Claude को एक तरह के manager की तरह इस्तेमाल करते हैं और code review और project management में सबसे ज़्यादा मदद मिलती है
- पूरे codebase पर problems, undeveloped areas, और future direction को सख्ती से ढूँढ़ने के लिए कहते हैं
- rejected approaches और बाद में किए जाने वाले features को docs और project memory में manage करते हैं
- garbage collector और memory allocator में Claude ने बेहतर algorithms सुझाए, जिससे बड़े सुधार हुए
- Lone में जाने वाली हर line को वे खुद review करते हैं, और code writing को भी educational मानते हैं, इसलिए AI पर Lone code लिखने के लिए भरोसा नहीं करते
- दूसरी ओर JavaScript static site generator में Claude से पूरे features लिखवाने का अनुभव रहा है
- planned features में GCC/Clang compiler API और stack protection functions का support शामिल है
Ruby और Scheme से लिया गया syntax
- वे Ruby की expressiveness और Scheme की संक्षिप्तता को जोड़ना चाहते थे; Lisp का parser सरल होने के कारण उसे खुद लिखा और nested lists को सीधे handle कर पाए
- Lisp को सच में समझने का क्षण तब आया जब उन्होंने ऐसा FEXPR implement किया, जिसमें function evaluated value नहीं बल्कि list खुद प्राप्त करता है
- array के लिए
[1 2 3], dictionary के लिए{k v}syntax इस्तेमाल होता है- यह Clojure और newLisp के साथ-साथ Ruby, Python, JavaScript users को भी परिचित लगता है, जिससे अनावश्यक entry barrier कम होती है
- C coding style के लिए Linux kernel style को संशोधित करके उपयोग करते हैं, लेकिन alignment और decoration कुछ अधिक पसंद करते हैं
- Ruby में
method('arg')की जगहmethod 'arg'जैसी कम punctuation वाली, English sentence के करीब शैली पसंद करते हैं - Lisp में भी syntax nesting कम रखते हैं
- Lone का
letरूप(let (a b c d ...) body...)है - पारंपरिक
(let ((a b) (c d) ...) body...)की तुलना में नाम और values का क्रमवार आना उन्हें function application style के अधिक स्वाभाविक लगता है
- Lone का
performance और bootstrap plan
- Lone जिस benchmark में आगे है, वह startup speed है; यह Ruby के Rubygems पढ़ने में लगने वाले समय से भी तेज़ program start और finish कर सकता है
- अस्थायी measurements में यह Python से लगभग 10~100 गुना धीमा है
- Lone, SICP अध्याय 5.4 जैसी संरचना वाला list-level interpreter है
- Python और Ruby bytecode interpreters हैं, इसलिए performance category अलग है
- lists को bytecode में बदलना उन्हें Lisp की प्रकृति खोने जैसा लगता है, इसलिए वे bytecode compilation से बच रहे हैं
- long term में C interpreter अंतिम bootstrap baseline के रूप में रहेगा, और JIT compiler Lone के भीतर ही लिखा जाएगा
- executable pages को
mmapसे लेकर उनमें instructions generate करने का तरीका अपनाया जाएगा
- executable pages को
- Bash के साथ recursive Fibonacci की अस्थायी तुलना में Lone बहुत तेज़ था, लेकिन वे मानते हैं कि Bash शायद हर iteration में process spawn कर रहा था, इसलिए measurement biased हो सकती है
- scripts में startup time महत्वपूर्ण होता है, इसलिए Lone का तेज़ bootstrap उपयोगी माना जाता है
- यदि hash tables को build stage पर precompute करके C initialization data बनाया जाए, तो runtime initialization cost और घट सकती है
memory और minimal environment
mmapkernel से memory pages मांगता है, और सामान्य page size 4,096 bytes होती है- read, write, execute permissions तय की जा सकती हैं, और JIT executable pages का उपयोग करता है
- अगर सिर्फ 16 bytes चाहिए लेकिन 4KiB मांगना पड़े तो बहुत बर्बादी होती है, इसलिए सामान्य allocator 128MB जैसे बड़े region लेकर उन्हें छोटे टुकड़ों में बाँटते हैं
- Lone के top-level environment में सिर्फ
importऔरexportदो symbols हैं- lists, literals, function-call mechanism के अलावा
if,quoteतक सब कुछ import करना पड़ता है - यह design user को environment के सभी names पर सीधा नियंत्रण देता है
- lists, literals, function-call mechanism के अलावा
- अभी लगभग 50 functions हैं, जिनमें
if,let,begin,control/transfer,intercept/signal,flattenआदि मुख्य हैं
standard library और documentation
- language docs अभी अधूरे हैं, लेकिन language features की तुलना में standard library का काम अब ज़्यादा करीब पहुँच रहा है
- Ruby की standard library और Scheme naming style से प्रेरणा लेने की योजना है
- अगला काम iteration protocol है
(for (each collection) (lambda (item) ...))जैसे रूप पर विचार किया जा रहा है- मौजूदा
eachfunctions को फिर से design करके सभी को generators लौटाने वाला बनाया जाएगा
- इसके बाद string manipulation और efficient concatenation के लिए string builder implement करना चाहते हैं
- iteration और string features पूरे हो जाएँ तो Hiccup-style web framework भी लिखा जा सकता है
- low-level features खत्म होने के बाद standard library के दोहराव वाले काम में ध्यान कम हो जाने की चिंता है, इसलिए Claude की management मदद लेने की योजना है
पूरे stack का स्वामित्व खुद रखने का लक्ष्य
- continuations जैसी रहस्यमय लगने वाली सुविधाएँ भी stack frame copy के रूप में समझी जाएँ तो सामान्य implementation problem बन जाती हैं; Lone का एक उद्देश्य यह भी है कि दूसरे लोग भी अपने systems बनाएँ और explore करें
- वे सिर्फ library consumer नहीं, बल्कि library बनाने वाले बनना चाहते हैं, और आम developers के लिए मानो निषिद्ध माने जाने वाले system calls को भी सीधे इस्तेमाल करना चाहते हैं
- अपना system रखने का मतलब है कि उसके टूटने पर उसे खुद ठीक करना पड़ेगा, लेकिन वे चाहते हैं कि ज़्यादा लोग उस ज़िम्मेदारी और उसके reward को चुनें
- उनका मानना है कि computing में जमा पुराने code से डरना नहीं चाहिए, और अनावश्यक layers हटाई जा सकती हैं
- Linux user space को फिर से बनाने वाला व्यक्ति वे नहीं, बल्कि कोई Rust या Zig developer भी हो सकता है
- Lone सफल न भी हो, तो भी अगर वह ऐसे प्रयासों को प्रेरित करे तो वे संतुष्ट होंगे
free software और Android
- वे free software के user empowerment वाले उद्देश्य को महत्व देते हैं, और इस बात को लेकर चिंतित हैं कि general-purpose computers कहीं companies या governments द्वारा नियंत्रित appliances में सिमट न जाएँ
- systemd को वे भले ही कुछ मामलों में भारी मानते हों, लेकिन पारंपरिक Linux user space को फिर से सोचने और rebuild करने का सफल उदाहरण मानते हैं
- उनका मानना है कि हर layer खुद बनाने के बजाय लड़ाइयाँ चुननी पड़ती हैं
- अगर Lone को bare-metal Lisp बनाया होता, तो शायद boot stage तक भी नहीं पहुँच पाते
- उदाहरण के तौर पर वे jart के 512 bytes से छोटे boot-sector Lisp, Sector Lisp, का ज़िक्र करते हैं
- Lone की शुरुआत Termux के अंदर हुई और इसका बड़ा हिस्सा mobile phone पर लिखा गया
- Android कुछ system calls, जिनमें
statxभी शामिल है, block करता है, लेकिन Lone Android पर चलता है और test suite 100% pass करता है
डॉक्टर और non-professional programmer
- Moreira 2019 में medical school से graduate हुए doctor हैं
- high school में neural network programming पढ़ते-पढ़ते उनकी रुचि biology में बढ़ी
- कुछ दिनों में वे 10~14 घंटे तक मरीज देखते हैं और कुछ दिन अवकाश जैसे होते हैं, जिससे programming के लिए समय मिल जाता है
- electronic medical records इस्तेमाल करने वाले hospital में templates और typing speed की मदद से वे काम का समय काफी घटा लेते हैं
- मरीजों से आँख मिलाते हुए भी records लिख सकते हैं
- हाल में शुरू किया गया Rails project उनकी अपनी ज़रूरत के लिए electronic patient record system है
- उनके अनुसार professional developers अक्सर अपनी व्यक्तिगत समस्याएँ खुद हल नहीं करते, उसका एक कारण computer itself में रुचि की कमी भी है
- सिर्फ result पाने की मानसिकता के बजाय जिज्ञासा चाहिए, तभी implementation के भीतर गहराई तक जाया जा सकता है; लोगों में वह जिज्ञासा कैसे जगाई जाए, यह उन्हें अभी नहीं पता
1 टिप्पणियां
Lobste.rs की राय
मुझे यह interview series इतनी पसंद है कि मैं इसे कभी मिस नहीं करता, और यह देखना बहुत दिलचस्प लगता है कि हर व्यक्ति का computing के साथ व्यक्तिगत रिश्ता कैसे बना
GBE+ GBA emulator के लेखक Shonumi भी मेरी तरह Mega Man Battle Network गेम से प्रभावित हुए थे, और मैं कभी उनका interview भी पढ़ना चाहूँगा
Restartable exceptions के लिए first-class continuation अनिवार्य नहीं है
Common Lisp, continuations के बिना भी restartable exceptions देता है, और इसका मूल बिंदु यह है कि handler को बुलाने से पहले stack को unwind नहीं किया जाता
इसलिए जिस stack और state में exception हुआ था, वह वैसा ही बना रहता है, और handler सामान्य रूप से return कर सकता है, या Common Lisp की तरह stack में कहीं मौजूद restart handler पर jump कर सकता है
लेकिन Lone Lisp में इसकी सचमुच ज़रूरत है, क्योंकि returned continuation को कई बार call किया जा सकता है और वह signal handler के बाहर भी निकल सकता है Generator बार-बार होने वाली processing की बुनियाद हैं, इसलिए वहाँ performance ज़्यादा महत्वपूर्ण है; इसी वजह से limited continuation की जगह अलग stack का उपयोग करके copying हटा दी गई
Error handling अपेक्षाकृत कम इस्तेमाल होने वाला path है, इसलिए वहाँ पूरा feature set देने का निर्णय लिया गया
बहुत से लोगों के लिए सबसे अहम काम या project शायद वही होता है जो वे फुर्सत में बिना किसी भुगतान, सिर्फ़ मज़े के लिए करते हैं
इससे मुझे यह कल्पना करने का मन हुआ कि शायद मेरा doctor भी चुपचाप अपनी खुद की Lisp language बनाने वाली दोहरी ज़िंदगी जीता हो
Dr. Cameron Kaiser ने भी बड़े projects किए हैं, machine ownership के बारे में अपनी दर्शन भी साझा करते हैं, और रोज़मर्रा में पूरी तरह खुला POWER9 workstation इस्तेमाल करते हैं
Lone Lisp के बारे में मैंने पहली बार अभी जाना, और यह एक शानदार project लगता है
मैंने भी लगभग 13~14 साल की उम्र में information class में पुराने Dev-C++ से C++ सीखना शुरू किया था, इसलिए यह याद अचानक बहुत nostalgic लगी
मुझे बिल्कुल उम्मीद नहीं थी कि वह doctor होंगे, और इससे Con Kolivas याद आ गए
लगता है ऐसे doctor-developers उम्मीद से कहीं ज़्यादा हैं
https://en.wikipedia.org/wiki/Con_Kolivas