Using Common Lisp in Emacs
Lisp is one of the oldest programming languages still in use today, but it has evolved in multiple directions over its more than 60-year history. Two of the more prominent descendants, Common Lisp and Emacs Lisp (or Elisp), are fairly closely related at some level, but there is still something of a divide between them. Some recent discussion in the emacs-devel mailing list have shown that some elements from Common Lisp are not completely welcome in Elisp—at least in the code that is maintained by the Emacs project itself.
The discussion goes back to at least mid-September when the subject of
keyword
arguments, which are used extensively in Common Lisp, came
up in
another context; at that time, Richard Stallman pointed out
that, while there is some amount of Common Lisp compatibility available for
Elisp, it is "not supposed to
be used a lot
". Alfred M. Szmidt concurred,
noting that useful pieces of Common Lisp can be adopted, but: "There is
no need to make
Emacs Lisp complicated for the sake of compatibility with Common Lisp.
"
Meanwhile, Emacs maintainer Eli Zaretskii quantified the
situation: "466 out of 1637 Lisp files in Emacs require cl-lib (some of them only
during compilation, i.e. they use only the macros).
" The Elisp "cl-lib"
library (formerly "cl", which is deprecated, as Emacs regularly tells me)
provides various compatibility macros and functions for those who need or
want to use
them in Emacs.
The conversation mostly dropped for a month, but Stallman picked it up
again in mid-October; he was trying to clarify how many uses of cl-lib in
Emacs were problematic. Using cl-lib for its macros, which only happens
at compile-time, is not really much of a problem in his view, but run-time
uses of the library may be more so. As he said in 2003, Stallman dislikes Common Lisp; he does "not have a very high
opinion of many of the decisions that were made in Common Lisp
",
keyword arguments in particular.
There are, Zaretskii reported, 226 run-time uses, which Emanuel Berg converted to percentages: 28% of Elisp files use cl-lib, 15% at compile time, and 14% at run time. Stallman said that he is most concerned with anything that might cause cl-lib to be loaded when Emacs is started without any customization (as when using the -Q command-line option).
Alan Mackenzie tried to
track down how many uses of cl- symbols there were in each of
the Elisp
files, suggesting that it would be a huge chore to remove all of them
"because there are enough contributors who
think that cl-lib is just an ordinary part of Emacs to be used freely
without restraint
", though he does not count himself among them.
Zaretskii questioned the numbers,
but said that some uses of cl-lib are likely unavoidable:
We cannot possibly expect people to contribute code if we force them not to use the macros they are used to. If cl-lib is not loaded as result, that is good enough for us, I think.
Berg wondered why it
mattered whether cl-lib was not being loaded under some circumstances;
"I think it is pretty clear that
cl-lib is used quite broadly, probably because people find
it useful.
" Zaretskii replied that it matters
because the project decided not to load cl-lib in "vanilla
Emacs
" because of "bloat,
unnecessary namespace pollution, etc.
" While cl-lib is not loaded for
"emacs -Q", Berg noted that it is
likely loaded soon after Emacs starts, since the debugger, native
compilation, and many other Emacs packages rely on cl-lib. Zaretskii was
unfazed by that:
What matters to us is that this unnecessary stuff is not loaded in "emacs -Q", i.e. is not dumped and preloaded into the bare uncustomized Emacs session. This lets users start from the leanest possible Emacs, then load what they need, without being "punished" by loads of stuff they never need or want.For Emacs to preload unnecessary stuff is unclean, and we try to avoid that uncleanliness.
There were arguments made that, these days, cl-lib was just an expected part of the Emacs environment, so perhaps it should be considered for preloading as well. As might be guessed, that did not really go far. In fact, the current long thread is an offshoot of one where switching Emacs to use Common Lisp was suggested as a way to reduce the C footprint of the editor. That went over even worse, unsurprisingly.
The main objection is that developers have to learn the Common Lisp functions and such in order to understand code that uses them. While Zaretskii sees no problem with developers using cl-lib in their own code or in Emacs extensions, he does not want to see it used in the vanilla Elisp code that gets preloaded when Emacs is started. Some see that as an ideological move, but Zaretskii said that it is simply a maintainability choice that the Emacs maintainers have made.
Stallman would like to go further, however; he sees the use of cl-lib by the debugger and native compilation extensions as problems to be solved:
Let's fix the debugger, and native compilation, not to load cl-lib.It's not so bad if you load a specialized package that serves your code and it uses cl-lib. But the debugger can be loaded to debug anything, even programs you have nothing to do with. It's rude for the debugger to load cl-lib.
Likewise for native compilation. You might recompile anything.
Zaretskii, however, does
not see those uses as problems at all (for
example: "The debugger uses cl-lib for good reasons.
"). He
said that he does not see a reason to "waste our resources
" on an
effort of that sort. Stefan Kangas concurred:
"let's focus our efforts on fixing real problems
".
Stallman did
a bit of digging into some of the entries in Mackenzie's list, finding
a false positive for byte-run.el, but also that the abbrev
minor mode uses the cl-pushnew
macro defined in cl-lib. "A generally useful minor mode as abbrev.el
should not load cl-lib.
" He suggested that the definition of
cl-pushnew should move
elsewhere so that it does not cause cl-lib to get loaded. Then the other
entries
on the list should be investigated and fixed as well. After that:
Once we fix them all, how about if we add a regression test to verify that various packages anyone might load at any time do not use cl-lib. With that, bugs like this would get caught right away.
Zaretskii pointed out
that cl-pushnew is simply a thin wrapper around another function
that is defined in cl-lib, so moving it would not stop the loading of the
library. Meanwhile, a regression test would be tricky to write "since
our test suite
infrastructure, ert.el, itself uses cl-lib extensively
". Stallman came up
with a different way to write the code that uses cl-pushnew,
but it was more verbose (and repetitive)—opinions varied on whether it was
truly an
improvement.
But these days, Zaretskii said, it is pretty much a
requirement for Emacs maintainers to "be familiar with the cl-lib and cl-macs
functionalities
" and that it is not rocket science to do so. Mackenzie strongly disagreed that it
was straightforward to pick up that knowledge:
I simply don't have the brain power to memorize such a morass of arbitrary, poorly named, poorly documented stuff. [...] I frequently spend, perhaps, half of my debugging time trying to understand what some cl-* does rather than concentrating on the problem to be debugged.
It is this added complexity that Stallman was trying to avoid when he
designed Elisp,
Bob Rogers said;
"he sees cl-lib.el as a trojan horse that is
changing Emacs Lisp
". Stallman agreed with
that, noting that he was under the impression that cl-lib was simply meant
as an optional extension, which is fine, but that he objects to it becoming
essential, which is where things are heading.
There is no sharp line between the one and the other, and no simple test to determine which of those two our current situation actually is. Rather, there is a spectrum that runs from "CL [Common Lisp] support is available but you can ignore it" to "the CL constructs are an essential and unavoidable part of Emacs Lisp."The specific practical questions I've asked are efforts to evaluate where we are now along that spectrum. Of course, the answer to that isn't precise either. But I was very surprised to learn how far Emacs has gone towards the latter end.
There are other libraries that add complexity to Elisp, however, so João Távora wondered what was special about cl-lib in this regard:
Then why this laser-focus on cl-lib.el? Why not criticize the use of seq.el and map.el and pcase.el all of which "add many functions, which have many details"? Why are these libraries seemingly exempt from this discussion?
He followed that up with some further analysis of the difference in the way cl-lib is treated; there are other additions to Elisp that have been adopted along the way, some of them to the point of being preloaded (such as the seq.el library for sequence functions) these days.
Part of the difference is that Stallman truly dislikes the prevalence of keyword arguments in Common Lisp, which is something that he does not want to propagate into Elisp. Some discussion of adding an Elisp pushnew to replace cl-pushnew made it clear that he did not want an Elisp version to support the latter's keyword arguments, thus it would not be a drop-in replacement. There are, Stallman said, some places where keyword arguments might make sense in Elisp, such as for sort, but that simpler functions and macros should not add them.
The proposed change to the abbrev minor mode, which would avoid
cl-pushnew, is not something that Zaretskii sees as needed, though
he would not object if "the result is clean, tested, and is not horribly
complicated
". There is "nothing wrong with loading cl-lib when its
facilities are put to a
good use
". Stallman disagreed
and said that he has "decided to start fixing some of those files not to
use the
run-time CL features
"
To an outsider, the push to avoid cl-lib (and Common Lisp, in general) in Emacs seems a bit strange and the "rules" governing its use seem fairly arbitrary—not even the creator and the current maintainers can agree. There is obviously a balance to be struck, for maintainability and for reducing the amount of Lisp constructs that Emacs hackers need to know, but one has to wonder if that balance has tipped too far in either direction. Stallman (and some others) clearly seem to think it has, but Common Lisp has a fair share of Lisp hackers as well—many using Emacs as their development environment—so the situation is a little puzzling, at least to this neophyte (Common) Lisp hacker.
Posted Nov 14, 2023 19:58 UTC (Tue)
by louai (subscriber, #58033)
[Link] (29 responses)
Posted Nov 14, 2023 21:32 UTC (Tue)
by neggles (subscriber, #153254)
[Link] (28 responses)
"I don't like thing"
Does an excellent job of alienating users and developers alike, and usually results in something that's good in theory but kind of mid in practice (e.g. GPLv3, which went a little too hard in a couple of aspects and shot itself in the foot by favouring ideology over reality)
Posted Nov 15, 2023 7:45 UTC (Wed)
by rsidd (subscriber, #2582)
[Link] (19 responses)
Posted Nov 15, 2023 7:59 UTC (Wed)
by jem (subscriber, #24231)
[Link] (17 responses)
This is not just about keyword arguments. From the mailing list: >Btw, the above is a very simple use of cl-loop. We have quite a few of much more complex ones. For example: Boy that is hard to understand.
Posted Nov 15, 2023 10:33 UTC (Wed)
by spacefrogg (subscriber, #119608)
[Link] (16 responses)
Posted Nov 15, 2023 10:58 UTC (Wed)
by Phantom_Hoover (subscriber, #167627)
[Link] (6 responses)
The fact that some Lisp advocates seem to seriously think ‘you use macros to create a DSL to solve your problems’ is an incredible selling point frankly baffles me. At best you’re reducing a variety of medium-difficulty problems into the hard problem of designing a decent computer language, and at worst… well if you asked me to maintain a legacy codebase full of ad-hoc half-finished DSLs I’d run a mile in the other direction.
Posted Nov 16, 2023 3:02 UTC (Thu)
by NYKevin (subscriber, #129325)
[Link] (5 responses)
As a complete outsider to this discussion... every time I read someone's argument for Why Lisp Is Great™, DSLs are always at the top of the list. Have I been misinformed?
I don't use Lisp, so I can't judge for myself.
Posted Nov 16, 2023 6:51 UTC (Thu)
by jem (subscriber, #24231)
[Link]
This reminded me of the attempt to introduce infix notation in Scheme, because prefix notation "does not feel natural". https://srfi.schemers.org/srfi-105/srfi-105.html
Posted Nov 16, 2023 13:02 UTC (Thu)
by Phantom_Hoover (subscriber, #167627)
[Link] (3 responses)
Posted Nov 16, 2023 17:11 UTC (Thu)
by Wol (subscriber, #4433)
[Link] (2 responses)
The other thing is, like me with Pick and Relational, Lisp is actually fundamentally different to other languages in many ways. Like Forth is fundamentally different. You know the quote about "BASIC considered harmful"?
The languages you know shape the way you think. For example, comparing those three languages, BASIC encourages/d long monolithic procedural code. There's no reason for it to be spaghetti, but it easily slips into it. Forth it's pretty much impossible to write monolithic code, it is structured functional code. Lisp, as its name implies, is very much data-driven structures. Those are three completely different ways of thinking, and for example comaparing C code written by a C expert with C code written by a Lisp expert who is good at C, even with them both tackling the same project their code will have a completely different feel. And quite possibly they would have difficulty understanding WHY the other one had done things a certain way, even if both ways worked very well. Lisp programmers think their approach is superior, and actually I believe the evidence bears that out. Even if writing C in the Lisp style actually results in a more efficient program!
Like me, my data tables have a completely different feel, in all likelihood, to a Relational guy. Because my Pick heritage means tables "just want" to be fourth normal form, because I do an EAR. My mindeset, the way I see data and code, is completely different to the way a Relational guy sees it. And of course, I think my way is best :-)
(The same analysis applies to natural languages. I'm multi-lingual - European languages only - and there are plenty of examples where different nations see things differently because only one language has the words to express something. Or the overtones of a direct translation give completely the wrong meaning - compare the English "borgeois" with the German "gut burgerlich", for example!)
Cheers,
Posted Nov 16, 2023 18:32 UTC (Thu)
by mpr22 (subscriber, #60784)
[Link] (1 responses)
I do. I also know people who studied computer science in the 1990s having had their first exposure to computer programming be 8-bit microcomputer BASICs; quite a few of those BASICs were arguably worse than the Dartmouth BASIC of 1975 that Dr Dijkstra was familiar with. Their minds have never struck me as "mutilated".
Posted Nov 16, 2023 23:02 UTC (Thu)
by Wol (subscriber, #4433)
[Link]
But as I say, my point is not that one language is better or worse than another, but that it shapes the way you see the world. The first languages you are taught often have a major impact on how easily you learn others. My first language was FORTRAN, and I'm sure (if you know FORTRAN), you would see the heritage even in the code I write today, 40 years on. As a simple example, when writing C I almost always use arrays, not pointers ... they may be functionally identical (near enough), but that's what seems natural to me. (And when given a C programming test by a recruitment consultant, my colleague and I got some of the highest scores the consultant had seen ...)
Cheers,
Posted Nov 15, 2023 11:40 UTC (Wed)
by mti (subscriber, #5390)
[Link] (7 responses)
When not using a language every day it is much easier to read code that uses a few simple constructs.
When using a language every day it may be different.
Posted Nov 15, 2023 12:37 UTC (Wed)
by spacefrogg (subscriber, #119608)
[Link] (6 responses)
The loop, with all its weaknesses, I grant you that, captures the meaning of the code much better, because everything that belongs to the loop is encapsulated by it. To do such abstractions is an essential property of high-level programming languages.
I find arbitrarily selected "I reject any further abstractions from this point on" to be no contribution to any debate about computer programming. There are valid situations to reject needless abstractions, but capturing loops is certainly not one of them.
All programs invent abstractions. When those abstractions are not represented in the programming language, they are called protocols or API.
Posted Nov 15, 2023 14:05 UTC (Wed)
by mti (subscriber, #5390)
[Link] (5 responses)
So, almost, but not completely unreadable ;-)
There is a balance in how much abstraction you use at the syntax level. Short common idioms are good for the experienced developer but can be hard to understand for the occasional developer.
Or expressed in another way. If I was developing Common Lisp software I would probably use cl-loop myself (*). When occasionally looking at elisp code I would prefer that the code does not use cl-loop.
(*) I assume it is called just 'loop' in CL, 'cl-' just being a prefix used in elisp?
Posted Nov 15, 2023 17:41 UTC (Wed)
by louai (subscriber, #58033)
[Link] (4 responses)
Posted Nov 15, 2023 17:44 UTC (Wed)
by louai (subscriber, #58033)
[Link]
Posted Nov 16, 2023 18:52 UTC (Thu)
by sfink (guest, #6405)
[Link] (2 responses)
First of all, what's the point of `with` bindings when they're outside of the loop anyway? Why should they be considered "part of the loop"? What's wrong with using `let*` to create an environment with the correct scope, given that that's what the programmer is expressing? I don't get it, and that made it harder for me to understand the `cl-loop` thing since I thought it couldn't possibly be doing the thing that seemed like a bad idea to do, so I tried to come up with some other meaning.
Second, the `for` keyword is absolutely baffling if you aren't already familiar. I would also assume it was doing some sort of triply-nested loop. If you want bindings in the loop body, wouldn't the most straightforward way to do that be to... put the bindings in the loop body?
`cl-loop`/`loop` just feels to me like it's trying too hard to be declarative or something, which creates a level-of-abstraction separation between the loop and its surroundings that feels jarring. Declarative is great. Imperative is ok. Mixing the two is a mess, and the benefits really have to pay for themselves.
I feel like I'm just not getting it. Which is unsurprising, since I've written almost no code in either CL or Elisp for multiple decades, and I'm unfamiliar with the conventions and space. So my opinion shouldn't carry much weight. But I'm offering it up as a datapoint about an external perspective.
Posted Nov 16, 2023 20:01 UTC (Thu)
by louai (subscriber, #58033)
[Link] (1 responses)
Posted Nov 16, 2023 20:07 UTC (Thu)
by louai (subscriber, #58033)
[Link]
Posted Dec 21, 2024 15:22 UTC (Sat)
by bpearlmutter (subscriber, #14693)
[Link]
Posted Nov 15, 2023 17:57 UTC (Wed)
by iabervon (subscriber, #722)
[Link]
Posted Nov 15, 2023 7:47 UTC (Wed)
by jem (subscriber, #24231)
[Link] (3 responses)
I understand Stallman's fear that the simplicity of Emacs Lisp is at risk if it turns into a combination of two languages: Emacs Lisp and Common Lisp. Completely replacing Emacs Lisp with Common Lisp is impossible at this point.
Do you have any statistics to back up your claim that Common Lisp is "what end-users and other developers actually want to see/use"? Maybe it is just a vocal minority on the emacs-devel mailing list?
Posted Nov 15, 2023 7:54 UTC (Wed)
by epa (subscriber, #39769)
[Link] (1 responses)
Posted Nov 15, 2023 8:10 UTC (Wed)
by jem (subscriber, #24231)
[Link]
Posted Nov 16, 2023 23:37 UTC (Thu)
by jschrod (subscriber, #1646)
[Link]
Why do you claim that these 30+% of package writers are "just a vocal minority on the emacs-devel mailing list"?
What would you demand for other statistics that would prove the point valid that these developers see cl-lib as a common part of Elisp, if 30+% of developers using it is not enough?
Do you demand explicit documentation that they consider the features of cl-lib good and usable?
Posted Nov 15, 2023 11:41 UTC (Wed)
by IanKelling (subscriber, #89418)
[Link] (3 responses)
> the reality of what end-users and other developers actually want to see/use.
"emacs lisp + common lisp" is obviously a bad bad language that emacs has good logical reasons to discourage. This is not an arbitrary RMS opinion.
Posted Nov 15, 2023 12:17 UTC (Wed)
by neggles (subscriber, #153254)
[Link]
Posted Nov 15, 2023 17:39 UTC (Wed)
by mpr22 (subscriber, #60784)
[Link]
If there's one thing having 20+ years experience in writing software has taught me, it's that very few things are actually obvious.
Posted Nov 16, 2023 23:27 UTC (Thu)
by jschrod (subscriber, #1646)
[Link]
I'm programming in Elisp and CL since 40 years. I don't think that "Elisp + CL" is bad.
Especially, I don't like intrusive hyperbole like "bad bad language" without any argument why that is so. Many people with decades of Lisp programming think otherwise.
IOW: Cut down in your quest to defend RMS and start to add something to the technical discussion.
Posted Nov 15, 2023 10:47 UTC (Wed)
by Phantom_Hoover (subscriber, #167627)
[Link]
Posted Nov 15, 2023 12:09 UTC (Wed)
by IanKelling (subscriber, #89418)
[Link] (3 responses)
Your comment might as well be "I like javascript. It is better than emacs lisp. It is better because X, Y, and Z." Ok, and you are totally missed the point. You can argue that any number of other languages are better than Emacs Lisp, but that doesn't mean Emacs is better off being some mix of several languages. Yes, it is great to be fluent in many programming languages, and when they are interoperable, being able to mix them is fun. But that doesn't mean that is the best or even good way to write code for other people to use. You already learned it, so who shouldn't everyone else? Because we've got limited time and brainpower. I'm pretty sure everyone else is better off not having to slowly learn the 110 page manual of the "partial" common lisp implementation in order to modify and extend emacs https://www.gnu.org/software/emacs/manual/html_mono/cl.html. The language "emacs lisp + lots of cl-lib" seems to me a very poorly designed language with tons of redundancy, and poor choice for the use case of being the language of emacs. Even the unrealistic hypothetical idea of converting emacs into common lisp is a bad idea because elisp is better suited to the job in many ways. Imo, emacs should be doing even more to discourage cl code in common emacs packages.
Posted Nov 15, 2023 12:13 UTC (Wed)
by IanKelling (subscriber, #89418)
[Link] (1 responses)
Posted Nov 16, 2023 22:28 UTC (Thu)
by louai (subscriber, #58033)
[Link]
The thing with Common Lisp is that there's a great manual to actually refer to. Of course
I came at Emacs from the other direction - I learned Common Lisp first, and then elisp. From that perspective elisp in some ways feels "impoverished", in the same way that for someone looking at it in the opposite direction Common Lisp might appear baroque.
There is nothing wrong with these other modules. But
For me this is a large part of the appeal of Common Lisp. The core is very stable and well specified. It has warts. It has many warts. But it's fundamentally quite sound and relatively coherent. And on top of it it's possible to implement just about anything. In some sense elisp is less stable - list manipulation libraries come and go, implementing and reimplementing the same thing in the currently fashionable style. This is because elisp is a very different thing from Common Lisp. Its core is smaller and doesn't need to be as general purpose.
I think people should be free to choose whichever approach they prefer. If you are at all a seasoned Lisp hacker you will not have problems following along. This isn't to say that everyone who contributes must be a master guru uber ninja. I'm saying there's room for both, and removing usages of
Posted Nov 15, 2023 13:01 UTC (Wed)
by spacefrogg (subscriber, #119608)
[Link]
What you are actually saying is: "It should not be allowed to write certain functions in elisp, because they would mimic functions in CommonLisp, which I don't like!" Well, you can do that, I suppose. I do not find this a valid opinion, though. Nobody, not you, not anyone else is telling me how to program and what functions to write to deliver a functionality. And if you want to meaningfully debug my code, you still have to understand how the functions, that I use, operate. So, forcing me to write my own abstractions, won't even help you debugging my code.
Emacs is a complex computer interface. It has to deal with all kinds of languages and also understands others than Elisp like XML or JS to provide valuable service to you. Do you want to forbid that as well just to keep a holy language clean?
People have put effort into writing emacs packages and they chose to use cl-lib, because it solved real problems for them that no other emacs developer or any programmer, including you, could be arsed to help them with.
I always find it funny when some "gray-beard developers" show up telling anyone how much easier it is reading the simple constructs of elisp and not having to read "110 page manual"s, while at the same time, newcomers, apparently, find it easier to just use the, oh so dreadful, cl-lib functions. How is it that those newcomers are so much cleverer learning new code constructs than you old big bosses?
I suspect it is you, who is completely besides the point. And I can, at the same time, completely respect the emacs maintainer's stance that they don't want do maintain code that needs cl-lib. Well, then they have to find somebody to clean up the code that exists and deter any newcomer from using cl-lib. And please, don't speak for "people". Speak for yourself. You have no idea what is "better for people" any more than I do.
Using Common Lisp in Emacs
Using Common Lisp in Emacs
"Well, we like thing"
"But I don't like thing!"
Using Common Lisp in Emacs
Using Common Lisp in Emacs
> with comp-ctxt = (make-comp-cstr-ctxt)
> with h = (make-hash-table :test #'eq)
> for (f type-spec) in comp-known-type-specifiers
> for cstr = (comp-type-spec-to-cstr type-spec)
> do (puthash f cstr h)
> finally return h)
I believe you know already that the loop code is equivalent to something like:
Using Common Lisp in Emacs
(let* ((comp-ctxt (make-comp-cstr-ctxt))
(h (make-hash-table :test #'eq)))
(dolist (x comp-known-type-specifiers h)
(let* ((f (car x)
(type-spec (cdr x))
(cstr (comp-type-spec-to-cstr type-spec)))
(puthash f cstr h))))
And now tell my how this, anywhere on earth, is easier to understand than the cl-loop macro. If you know anything about the cl-loop macro, you realise that "with ... =" is a let binding before the loop and "for ... =" is a let binding inside the loop. "for ... in" is obviously the loop itself. And even if you don't know cl-loop specifically. You can roughly infer the idea by just using common understanding of the English language and common use of trigger words like "with" and "for". Even elisp itself uses the with-* metaphor to signify temporary bindings. So I call this whole previous comment a straw man.
You may dislike the loop macro anyway you want. I do, too. But calling it unreadable is not serving any constructive purpose.
Using Common Lisp in Emacs
Using Common Lisp in Emacs
Using Common Lisp in Emacs
I wouldn’t say you’re ‘misinformed’, this is very much my own hot take. But I have had to maintain and extend software written in a DSL by someone who was clearly bored and had since left. Fortunately it was a simple script that could be unpicked in an hour or two, and easily rewritten in the base language; if it had been substantially more complex, and used more of the DSL’s unique functionality, understanding what it was actually doing and fixing or extending it would have been extremely difficult — I’d probably still have extracted all the logic and rewritten it in the base language that I and my colleagues are familiar with.
One of the most difficult and important challenges in software design is making architectures that are flexible, extensible and maintainable by many people over many years, and language design is a fairly pure example of that. It’s insane to me that anyone thinks it’s a good choice of tool for problems like formatting a string or writing loops. Remember that CL’s format and loop DSLs are mature standards, despite all their complexity — imagine trying to work with them in the more common scenario where they’re legacy code, half finished and written by someone you can’t contact.
I honestly think the reason Lisp fans talk so glowingly about this approach is that CL is only used by hobbyists or small companies with low churn. (I do still like it a lot though, it was the second language I learned and I’d happily work with it over most mainstream languages.)
Using Common Lisp in Emacs
Using Common Lisp in Emacs
Wol
Using Common Lisp in Emacs
You know the quote about "BASIC considered harmful"?
Using Common Lisp in Emacs
Wol
Using Common Lisp in Emacs
Using Common Lisp in Emacs
Using Common Lisp in Emacs
Yes in Common Lisp it's just Using Common Lisp in Emacs
LOOP
.
You might write something like this:
Roughly equivalent to this C++ code with made-up types:
(defun frob-type-specifiers (specifiers)
(loop with comp-ctxt = (make-comp-cstr-ctxt)
with h = (make-hash-table :test 'eq)
for (f type-spec) in specifiers
for cstr = (comp-type-spec-to-cstr type-spec)
do (setf (gethash f h) cstr)
finally return h))
To a trained eye the loop construct is much easier to grok since it encapsulates all the relevant variables in one place. The
std::unordered_map<f_t, cstr_t>
frob_type_specifiers(const std::vector<std::pair<f_t, spec_t>> &specifiers) {
auto comp_ctx = make_comp_cstr_ctxt();
std::unordered_map<f_t, cstr_t> h;
for (auto &it : specifiers) {
auto f = it.second.first;
auto type_spec = it.second.second;
auto cstr = comp_type_spec_to_cstr(type_spec);
h[f] = cstr;
}
return h;
}
with
clauses create variables that have block scope. The for
clauses create variables that have loop iteration scope. The do
clause does something on every iteration. The finally
clause can be used to do something when the loop terminates.
Of course those C++ assignments should be
Using Common Lisp in Emacs
auto f = it.first;
auto type_spec = it.second;
Using Common Lisp in Emacs
Here is a detailed look at the Using Common Lisp in Emacs
LOOP
macro.
Admittedly it is divisive - some people love it, some hate it. But it's also very powerful. I'll pick an example from the link above with a couple comments:
;; List of 100 random numbers under 10000
(defparameter *random* (loop repeat 100 collect (random 10000)))
;; Iterate over *random* counting even and odd numbers, calculating
;; a total sum, and grabbing smallest and largest elements
(loop for i in *random*
counting (evenp i) into evens
counting (oddp i) into odds
summing i into total
maximizing i into max
minimizing i into min
finally (return (list min max total evens odds)))
Apologies for the self-reply, I accidentally hit publish when I meant preview. Here's an example from a personal project, to convert LEB128 octets to integers:
Using Common Lisp in Emacs
It's a powerful tool that makes for very succinct loops. Like any powerful tool it does require some practice to use properly. I feel that is very much in the Emacs tradition though.
(declaim (inline unsigned->signed))
(defun unsigned->signed (n size)
(logior n (- (mask-field (byte 1 (1- size)) n))))
(defun leb128->integer (chunks &optional signed)
(loop for bits from 0 by 7
for chunk in chunks
for septet = (mask-field (byte 7 0) chunk)
for result = septet then (dpb septet (byte 7 bits) result)
finally (return (if signed
(unsigned->signed result bits)
result))))
Minor bug: you forgot to return Using Common Lisp in Emacs
h
. You need an h
after the (dolist ...)
.
Using Common Lisp in Emacs
Using Common Lisp in Emacs
Using Common Lisp in Emacs
Using Common Lisp in Emacs
Using Common Lisp in Emacs
Using Common Lisp in Emacs
Using Common Lisp in Emacs
Using Common Lisp in Emacs
Using Common Lisp in Emacs
Using Common Lisp in Emacs
Using Common Lisp in Emacs
Using Common Lisp in Emacs
Hi Ian,Using Common Lisp in Emacs
cl-lib
isn't a complete replacement for it, in the sense that it's incomplete. So I do agree that it's not a perfect situation.cl-lib
fills many of those gaps with the useful delta that has accumulated over time. I think the gaps are real, because there exist various elisp modules to provide utilities that are similar to those that cl-lib
provides, for example seq.el
and dash.el
.cl-lib
has one advantage: it can actually draw from an ANSI standard that won't change. That gives the idioms that it implements, even if they aren't precise, complete implementations of what Common Lisp specifies, a certain stability and predictability. It's not going to go away, and I don't have to think about these things after I've learned them once.cl-lib
for the sake of removing usages of cl-lib
isn't a very productive endeavor. And I think if you need to learn how some code that uses cl-lib
or seq.el
or dash.el
works, you will find the overhead of learning these utilities to be smaller than the overhead of learning how the main module works. I just don't see it as an issue.
Using Common Lisp in Emacs