- 1989 का FM TOWNS के लिए High C Compiler सिर्फ DOS environment compatibility तक सीमित नहीं था, बल्कि उस समय के C compilers में दुर्लभ कई user-oriented language features भी शामिल करता था
- Phar Lap के DOS extender के साथ जुड़कर यह 16-bit MS-DOS environment में 32-bit 80386 का उपयोग करने वाली development workflow का हिस्सा बना, और FM TOWNS का 1st-party C compiler बन गया
- numeric literal underscore, labeled arguments, case ranges, nested functions, generators जैसी सुविधाएँ C/C++ standard में बहुत बाद में आईं, या आज भी standard में नहीं हैं
- nested functions ने function pointer और context pointer को साथ ले जाने वाले non-escaping closure के रूप में “full function value” दिया, जो सामान्य C function pointer से अधिक expressive था
- generators को nested functions के ऊपर syntactic sugar के रूप में लागू किया गया था, इसलिए caller के
forloop body को nested function में बदलकर उसेyieldargument के रूप में पास करने वाली सरल संरचना से यह काम करता था
FM TOWNS और High C की जगह
- FM TOWNS से जुड़ी किताबों के ढेर में मिला 1980 के दशक का यह C compiler manual उम्मीद से कहीं अधिक समृद्ध language extensions रखता था
- C और उससे जुड़े language family को वास्तविक environments में इस्तेमाल करने के लिए लंबे समय तक vendor extensions की ज़रूरत पड़ती रही
- आज के GCC, Clang, MSVC-केंद्रित environment में extensions ज़्यादातर platform-specific handling या low-level control पर केंद्रित रहती हैं
- 1980 के दशक में छोटी और अधिक कंपनियाँ adoption के लिए प्रतिस्पर्धा कर रही थीं, इसलिए extension features भी अधिक विविध थीं
- Phar Lap ने 16-bit MS-DOS environment में 32-bit 80386 processor का उपयोग संभव बनाने वाले शुरुआती DOS extender में से एक बनाया था
- MetaWare ने Phar Lap के अनुरोध पर High C Compiler को Phar Lap के DOS extender SDK पर port किया
- Fujitsu ने 803386-आधारित FM TOWNS platform OS में Phar Lap के DOS extender को integrate किया, और High C इस platform का 1st-party C compiler बन गया
- FM TOWNS 1989 में लॉन्च हुआ, ठीक उस समय जब पहला ANSI C standard C89 अनुमोदित होने वाला था
standard से आगे की छोटी सुविधाजनक features
-
numeric literals में underscore separators
- लंबे numeric literals को पढ़ने में आसान बनाने के लिए अंकों के भीतर underscore separators डाले जा सकते थे
- C++ ने C++14 में
1'000'000जैसे apostrophe separators जोड़े - C ने C23 में जाकर ही ऐसा मिलता-जुलता feature अपनाया
-
labeled arguments
- जिन functions में parameters बहुत हों, या
boolजैसे ऐसे types अधिक हों जिनका अर्थ call site पर स्पष्ट न हो, उनमें argument names लिखे जा सकते थे - High C के labeled arguments Python की एक लोकप्रिय feature की तरह काम करते थे
- argument labels optional थे
- label होने पर
argumentName => valuesyntax के साथ arguments को किसी भी क्रम में दिया जा सकता था - unlabeled और labeled arguments को मिलाया जा सकता था, लेकिन function के सभी parameters के लिए matching arguments होना ज़रूरी था
- standard C और C++ में यह feature अब भी नहीं है
- जिन functions में parameters बहुत हों, या
-
case ranges
- Pascal के
case low..highकी तरह एक बार में value range match करने की सुविधा दी जाती थी - standard C और C++ ने यह feature नहीं अपनाया
- Pascal के
nested functions और full function value
- High C, Pascal की तरह, function के अंदर nested functions declare करने देता था
- इसका implementation standard Pascal या GCC के nested function extension की तुलना में अधिक complete रूप के काफ़ी करीब था
- High C सिर्फ nested function declarations ही नहीं, बल्कि full function value type भी declare कर सकता था
- पारंपरिक C function pointer के विपरीत, यह function pointer के साथ context pointer भी रखता था
- इससे nested function द्वारा captured context को फिर से पाया जा सकता था
- यह एक non-escaping closure था, जिसकी lifetime outer function के return होने के बाद तक नहीं बढ़ती थी
- GCC का nested function extension nested function को सामान्य function pointer की तरह refer करने के लिए call stack पर executable code लिखकर context pointer को thunk करता था
- इस तरीके ने बड़े security risk पैदा किए, और कई platforms ने इस feature को पूरी तरह disable कर दिया
- High C के local function references first-class values की तरह इस्तेमाल किए जा सकते थे, लेकिन उनकी lifetime outer function के return के बाद तक extend नहीं होती थी
- nested functions parent function में
gotoभी कर सकते थे- Smalltalk blocks की तरह non-local exit संभव था, यानी nested function के बाहर निकलना
- इससे control flow की तरह व्यवहार करने वाले functions बनाए जा सकते थे
- Objective-C को 2009 में escaping closure के रूप में इस्तेमाल किए जा सकने वाले blocks मिले, और C++ ने 2011 में lambdas पेश किए
- इन दोनों में non-local exit की क्षमता नहीं थी
- standard C में अब भी कोई आधिकारिक nested function feature नहीं है
generator coroutines
- MetaWare ने generators feature पर इतना ज़ोर दिया कि उसके लिए पूरा एक chapter समर्पित किया
- High C ने 1989 में plain C में Python-style generator coroutines का समर्थन दिया था
- generator function को
void foo(Arg arguments) -> (Yield yields)syntax से declare किया जाता था- function के भीतर magic function
yield(values...)को कई बार call करके values की sequence बनाई जा सकती थी - caller
for variable... <- foo(arguments...) do { ... }रूप की नईforloop syntax से generated values को क्रम से iterate करता था
- function के भीतर magic function
- यह implementation nested functions के साथ जटिल रूप से combine हो सकता था
- generator के अंदर nested functions outer generator के
yieldbehavior को capture कर सकते थे - nested function खुद को recursively call करके tree या recursive data structures को traverse करते हुए हर step पर
yieldकर सकता था
- generator के अंदर nested functions outer generator के
- यह रूप Python या कई mainstream generator coroutine languages की तुलना में ऐसा लगता है जिसे implement करना कठिन होगा
generator implementation और standard languages से अंतर
- High C के generators किसी advanced runtime के बिना, nested functions के ऊपर syntactic sugar के रूप में काम करते थे
void foo(Arg arguments) -> (Yield yields)रूप की generator declaration वास्तव में सामान्य function declarationvoid foo(void yield(Yield yields)!, Arg arguments)के बराबर थीyieldएक implicit parameter था, जिसका type “full function value” होता था- generator body के भीतर
yield(values)calls वास्तव में इसी implicit function parameter को call करने वाले सामान्य function calls थे
- caller side पर
forloop body को nested function में बदला जाता था- यही nested function generator के
yieldargument के रूप में pass किया जाता था - संरचना सरल थी, लेकिन प्रभावी थी
- यही nested function generator के
- क्योंकि nested functions non-local exit को support करते थे, इसलिए
forloop body के बाहर जाने वालेbreak,continue,gotoभी उपयुक्त loop-बाहरी स्थान परgotoकरके काम करते थे - standard C के ऐसे features को integrate करने की संभावना कम लगती है
- C++20 compile-time coroutine transformation पर आधारित बहुत flexible और complex coroutines feature देता है
- इसका उपयोग generators implement करने के लिए किया जा सकता है
- लेकिन उसका परिणाम local functions के साथ इस तरह सहज रूप से combine होता नहीं दिखता
1 टिप्पणियां
Hacker News राय
सौभाग्य से मेरे पास High C/C++ Language Reference का एक English edition है
http://jdebp.uk./FGA/metaware-iterator-driven-for.html
http://jdebp.uk./Proposals/metaware-iterator-driven-for.html
breakयाreturnकैसे compile होते होंगे। क्या इसे इस तरह transform किया गया होगा किyieldfunction एक status code return करे और call site पर उसकी जाँच हो?caseranges, named arguments, nested functions, static nested functions, generator जैसी functionalityउदाहरण के लिए
int a = 1_234_567;,case 5 .. case 6:,test(b:3, a:4);जैसे forms संभव हैंstatic nested functions बाहरी function के frame variables को access नहीं कर सकते, इसलिए
Error: static function test.foo.plus cannot access variable i in frame of function test.fooजैसी error आती हैgenerator जैसी functionality https://dlang.org/spec/statement.html#foreach_over_struct_an... में है
उदाहरण के लिए, अगर आप in-memory cache service बना रहे हों, तो cache items को खुद garbage collector द्वारा track न किया जाना बेहतर है। garbage collector को अक्सर असली access patterns नहीं पता होते, इसलिए वह बाधा बन सकता है। लेकिन उस service के बाकी ज्यादातर components के लिए garbage collector होना ज्यादा उपयुक्त है
named arguments
test(a:4, b:3)के रूप में क्यों हैं,test(.a=4, b.=3);के रूप में क्यों नहीं?यह भी जानना चाहता हूँ कि C में first-class types को कैसे handle किया जा सकता है
lcc-winC compiler ने operator overloading, default function arguments और function overloading जोड़े थे। documentation में “generic functions” देखें [1]Plan 9 C compiler ने भी कई language extensions introduce किए, जिनमें anonymous structs/unions जैसे कुछ बाद में C standard में शामिल हुए। आज GCC
-fplan9-extensionsflag accept करता है [2], जिससे function calls और assignments में struct pointers को anonymous fields में automatically convert करने जैसी काफी उपयोगी सुविधाएँ enable की जा सकती हैं[1] https://lcc-win32.services.net/C-Tutorial.pdf
[2] https://gcc.gnu.org/onlinedocs/gcc/Unnamed-Fields.html
अफसोस है कि ये दुनिया में व्यापक रूप से फैलकर language standards को प्रभावित नहीं कर पाए। इतनी पहले ऐसे features मौजूद थे, यह हैरान करने वाला है
Hacker News पर भी पहले इस पर चर्चा हुई थी: https://news.ycombinator.com/item?id=38938402
क्या कहीं इसकी PDF copy होगी?
yieldवाला for loop मौजूद था [0]. उसी दौर की Icon language में भी मिलती-जुलती generator functionality थी [1], और उसमेंyieldकोsuspendकहा जाता था। मेरी जानकारी में Ada (1983) में भी यह feature थाये language features पूरी तरह अनजाने नहीं थे
[0] https://publications.csail.mit.edu/lcs/pubs/pdf/MIT-LCS-TR-2...
[1] https://dl.acm.org/doi/pdf/10.1145/800055.802034
इसमें numbers के अंदर underscores,
caseranges, named parameters, nested functions, और full function variables तक समझाए गए हैंhttps://bitsavers.org/pdf/metaware/…
file के अंत से करीब 50 pages पहले Appendix A देखें
पहले जब मैं code सीखता और इस्तेमाल करता था, तब कुछ थोड़ी shady sites के जरिए उनके बारे में पता चला था
systems programming languages का समृद्ध इतिहास भी दिखता है। यह भी दिखता है कि C और Go की design इस मामले में कितनी समान है कि उन्होंने दूसरे ecosystems में हो रहे काम और पुराने अनुभवों को नजरअंदाज किया
कंपाइलर मैनुअल का लिंक https://winworldpc.com/product/metaware-high-c-cpp/33x पर है
C मैनुअल PDF में 2007 का copyright notice है
https://f.duriansoftware.com/@joe/113195961485703110
\nके बजाय¥nपर क्यों खत्म होते हैं, तो लगता है ये code examples Shift-JIS में लिखे गए थे। Shift-JIS में ASCII के\वाले स्थान पर¥आता है[0] https://en.wikipedia.org/wiki/JIS_X_0201
इस उपयोग के लिए EUC-JP बेहतर है, क्योंकि उसमें यह समस्या नहीं है। Pascal में अगर आप
(* *)comments इस्तेमाल करते हैं और{ }comments नहीं, तो Shift-JIS के साथ भी यह समस्या नहीं आतीइसके बजाय संभवतः Shift-JIS का आधार बने JIS X 0201(https://en.m.wikipedia.org.org/wiki/JIS_X_0201) का इस्तेमाल हुआ होगा
C:\नहीं बल्किC:¥होता थाCall (Param_A => 1, Param_B => "Foo");जैसे labels, arbitrary-base numbers में underscores (X : Integer := 1_000;), nested subprograms, और range-based checking होती हैहम अक्सर भूल जाते हैं कि उस समय C कई दूसरी भाषाओं की तुलना में अविश्वसनीय रूप से primitive था
मुझे जापानी notation या kerning rules की पर्याप्त जानकारी नहीं है, लेकिन ऐसा दिखता है जैसे Kanji और Latin characters दोनों वाले variable-width font को fixed-width cells में जबरन fit किया गया हो
खैर, अच्छा है कि code examples मेरी कई किताबों की तरह 8pt font में नहीं हैं
try_fold()याद आते हैं (https://scribe.rip/@veedrac/rust-is-slow-and-i-am-the-cure-3...)लेकिन शायद इसी वजह से ये extensions तुलनात्मक रूप से कम जाने गए, और दशकों बाद modern C/C++ में इन्हें फिर से खोजना और reinvent करना पड़ा