|
* Fexprs are easier to write and more expressive than macros. They can be mapped, applied, wrapped around other functions, fexprs and built in primitives, in the case of Newlisp, even mutated during runtime. Fexprs are lot of fun. And the price is - dynamic scope. More about dynamic scope later. * ORO is something in between "manual" memory management like in assembler in C and real GC. It is "more automatized" than former, and less automatized than later. Basically, i agree with you, GC has some important advantages, but ORO is - adequate - and I'd say, not completely without advantages in practice as well. (Theoretically, GC is not excluded in the form of libraries. In past there was little interest for that, but Greg's recent "Objective Newlisp" library provides simple, reference counting-based GC algorithm.) * Dynamic scope - it gives more expressive power: the functions in dynamic scope are about equally expressive as macros, and they are the first class values. The problem with dynamic scope is - accidental name clashes, or "overshadowing." That is where static scope helps and I understand it is reasonable choice for languages like Ada, Eiffel and many others: safety over expressiveness. However, it was not original design goal of Lisp, supposed to be very adventurous language - and it is still visible: CL, Scheme and Clojure programmers have to face exactly the same problem if they write macros. The solutions: namespaces, gensyms and "hygiene" work on the same or similar way for Newlisp dynamic scope. So, it is not really consistent to complain against dynamic scope as unsafe, and to believe that macros are (or can be) "safe enough." |
Dynamic scope is not about 'power', initially it was an implementation error. Then it stayed in Lisp for a while. Unfortunately most Lisp compilers implemented lexical scope (also because it runs faster), while interpreters stayed with dynamic scope. With Scheme the whole thing got cleared up and interpreters and compilers of the same language now were using lexical scope. Dynamic scope was now an extension (so-called 'fluid lets'). The developers of Common Lisp accepted that this was the right thing (like anyone else in Functional Programming and most Lisps like ISLisp, EuLisp, Dylan, ...) and adopted lexical binding, also requiring that the compiler and interpreter behave the same. Common Lisp additionally allowed to use dynamic binding when declared, because in many places it is a useful feature - just not be default.
The so-called 'Newlisp', from 1991, invented some of their own ideas, went back to old ideas and reused names (like 'macro' for 'fexpr') in confusing ways. The thing where it gets stupid is where people believe that it is 'better designed' (it is as ugly as most Lisps) or that it is 'faster' (for constructed benchmarks).
The problem with dynamic scope is not name clashes. The problem is that I don't know what bindings MY code will use, because somebody else might have rebound variables or functions in his code. That's the purpose of dynamic binding: injecting new bindings into old code. Additionally it is bad for compiled code, etc.
Newlisp is full of potentially scope problems and writing anything larger than a small script with FEXPRs is a maintenance nightmare. There has been lots of code being written with FEXPRs in the past, but today it is gone. Much of the dynamism that it provides is just not needed and simply gets in the way. One can generate artificial requirements where FEXPRs would be useful, in practice they are a relict of the past. Scheme and Common Lisp and all the other lexical scoped dialects are plenty expressive.