|
|
|
|
|
by hollerith
4259 days ago
|
|
Having spent a lot of time with Haskell and Scheme, what irks me the most about working in Emacs Lisp is the fact that it usually involves too much rigamarole or just fails to work for me to use a function that takes a function as an argument or returns a function as a result. E.g., in Haskell, I am fond of using `flip` to reverse two actual arguments just because it makes a line or 3 of code look nicer, and I cannot do that in Emacs Lisp -- or I can, but it involves adding additional lambda forms or calls to funcall or symbol-function (i.e., it involves too much rigamorole). Since I cannot say exactly how far lexical scoping would go in making Emacs Lisp more like Haskell in this regard, this is only a partial answer to your question, but certainly, the lack of lexical scope has something to do with it. Aside from the deficiencies I just mentioned around higher-order functions, I was surprised by how little the lack of lexical scope got in my way. (My reading of the computer-science literature had given me the impression it would cause more trouble than it actually does.) |
|
Getting back to actual question: Elisp supports "real" lexical scoping since previous major Emacs version, and it has had "lexical-let" and other such forms since forever, but most of the code is still dynamically scoped. In practical terms it's similar to having every variable declared as global - it allows for "out of band" communication (outside of arguments passed/value returned) between routines. This is sometimes handy if you want to change some function behaviour in a way that it didn't think of (ie. it has no argument dedicated for this). As a very contrived example, if you have a routine which beeps furiously every time you invoke it and you find it unbearable (I did) you can instead call it like this:
And it won't beep any more. A real life saver sometimes ;)On the other hand, every out-of-band communication has a set of problems to it: you can forget to check it, or you can accidentally pass something to a called function you didn't want to. In practice this is worked around with using longer, prefixed identifiers and the semantics of `let`. As long as every variable your function uses is let-bound inside it it is essentially safe to call with any kind of environment, as it won't ever look at it. Most functions are like that.
In short, dynamic scoping has it's advantages and drawbacks, and it feels quite well suited to an extension/scripting language of an app. It makes certain patterns easy enough that they don't even need a name ("monkey patching"), and it makes others much harder (like the linked dash-functional library, which would be very hard to write without lexical-scoping: t).