Co jsem do té knihy koukal ... mně LISP přijde spíš jako write-only jazyk určený pro snadné řešení problémů, a ne jako jazyk určený pro psaní aplikací.
Silný makrojazyk ... nepřijde mi to jako výhoda pro psaní aplikací. Příklad: v Linuxu třeba najdeš volání funkce outb_p. Nicméně definici té funkce tam v arch/x86 nenajdeš. Nenajdeš ji proto, že je generovaná makrem a i její jméno je také poskládáno makrem. Někdo zjistil, že outb_p, outw_p a outl_p mají podobnou implementaci a vygeneroval ty funkce z jedné šablony makrem --- sice můžeme říct, jak to krásně faktorizoval, a jak sdílel podobný kód --- ovšem má to i podstatnou nevýhodu --- když se jako nováček neznalý Linuxového kernelu podíváš na nějaký kód volající outb_p a zeptáš se "co to volání dělá?", tak se to nedozvíš.
Pokud někdo bude do důsledků používat to metaprogramování (makra nebo eval), jak to po něm přečteš? On sám to přečte, ale jak to přečte někdo jiný?
Když chceš něco změnit v programu v C, tak to tam najdeš, snadno zjistíš jak to funguje (až na pár extrémních případů, jako výše popsaný identifikátor skládaný makrem) a změníš to. Nemusíš vůbec zkoumat, jak celý program funguje ani jakou má strukturu.
Když chceš něco změnit v programu v C++, už je to horší, už to tak snadno nepochopíš, operátory mohou být přetížené (a nevíš na co, dokud neprozkoumáš celou objektovou hierarchii), u virtuálních metod také nevíš, co se volá.
A v případě jazyků ve kterých programátor definuje vlastní lexikální strukturu, jak zjistíš, co některá část dělá? ... leda přečtením a pochopením celého toho makrosystému, co si programátor nadefinoval.
Další otázka je, jak budeš takový meta-generovaný program ověřovat. U normálních jazyků, když chceš ověřit zda o proměnných X, Y a Z platí predikát P(X,Y,Z), tak je to jednoduché --- ověříš, že P(X,Y,Z) platí na začátku, a pak si grepem najdeš všechna místa, kde se X, Y nebo Z přiřazuje, a lokálně pro každé místo ověříš, že pokud platilo P(X,Y,Z) před přiřazením, pak musí platit i po přiřazení. V momentě kdy začneš ten kód dynamicky generovat, tak už to ověříš o hodně hůř --- musíš najít všechna místa, co generují nějaký kód, zjistit, zda se náhodou nesnaží vygenerovat kód, co přiřadí do X, Y nebo Z, a pokud ano, dokázat, že všechny možné varianty kódu, co vygenerují, zachovávají predikát P.
Jiný příklad --- u normálního jazyka můžeš jednoduchou flow-control analýzou dokázat, že funkce F nesahá na proměnnou X, funkce F nebere zámek Z, atd. V momentě, kdy funkce F pouští něco, co bylo někde vygenerováno, tak to už flow-control analýzou nedokážeš.