Lisp code is written top to bottom, left to right. Is your grievance more to do with expression-oriented—as opposed to statement-oriented—languages? "Do this" (statement) vs "represent this" (expression)? For instance, do Haskell, OCaml, etc. also irk you in similar ways?
(defun f (x)
(let ((y x))
(setf y (* y x))
(block foo
(if (minusp y)
(return-from foo y))
(loop :for i :from 1 :to 10 :do
...
This is absolutely typical bog-standard left-to-right top-to-bottom structured programming type code. It also must be executed like so:
- Define the function
- Bind the variable
- Mutate the variable
- Set up a named block
- Do a conditional return
- Run a loop
- ...
The order of execution literally matches the order it's written. But not unlike almost all other languages on the planet, expressions are evaluated inside-out.
Haskell's whole raison d'etre is to allow arbitrary nesting and substitution of terms, and all or none of these terms may or may not be evaluated depending on need. De-nesting happens with a copious number of syntax to bind names to values, sometimes before the expression (via let), sometimes after the expression (via where), and sometimes in the middle of an expression (via do).
This is a common reaction/belief but usually from people who have not actually managed a team of Lisp devs.
Lisp devs are managed in the same way as any other: You have style guidelines, design review, code review, etc. Sometimes a new macro is good and vastly simplifies code. It's accepted as a PR and documented like anything else. Sometimes a new macro is bad, and it's promptly rejected by the team. It's a persistent myth that Lisp programmers are just going to design their own little languages everywhere in a shared code base and it'll be impossible to understand.
(Case in point: Look at open source Lisp code. There isn't even management or code review there! Yet the vast majority of Lisp code is actually just functions and classes, with the occasional macro to reduce boilerplate. In some circumstances, you have a library offering a macro, and it's actually well documented and easy to understand. See Iterate, SERIES, etc. for actual examples.)
Rust or Elixir or Java or whatever aren't at all immune to monstrosities created by astronomically complex or baroque abstractions, FactoryFactoryFactories, and so on. How do teams avoid those? Style guidelines, design review, code review, etc.
It's hard to reconcile that with the comment they were responding to that claimed that lisp requires you to be the designer of the language a bit. I don't know enough to know who is right, but if the majority of the code is "just" regular functions and classes then I'd argue that it doesn't require custom design as a much as allow it, and the solution you're proposing is to mostly disallow it by convention. Like the comment you're responding to suggests, it's hard for me to imagine why having that much flexibility is worthwhile if it's going to be mostly unused when you can still write that occasional macro you call out in Rust or Elixir.
Lisp isn't solely defined by DEFMACRO. There are other reasons to use it too, in ways that can complement or compete with DEFMACRO. I also don't really know or understand what the term "flexible" is supposed to mean precisely. What makes a Rust macro less flexible than a Lisp macro in the context of this discussion? In particular, what do Rust macros tamp down on in terms of power that make them more justified for occasional use compared to a Lisp macro?
Lisp has a handful of language features that allow the definition of new syntactic abstractions: form level (DEFMACRO) and character level (SET-MACRO-CHARACTER). Just like it has operators to define new data structures (DEFSTRUCT and DEFCLASS). Just like it had operators to define new functions (DEFUN, DEFGENERIC, DEFMETHOD). Each of these defining forms materially change the way a programmer writes code. You don't need to add new syntax to change the language, and each kind of language change comes with its own tools and practices for working with them, debugging them, documenting them, and so on. All of this is to say: I don't see a good reason to have all of these remarks about syntactic abstraction when they very well could be made about data abstraction or control abstraction.
A useful language feature isn't something that needs to be maximized in idiomatic code. Syntactic abstraction is useful when it's useful, and when it is useful, it's usually extraordinarily useful—typically because a new syntactic abstraction allows a programmer to specify something much more directly or correctly than otherwise. (Other languages frequently resort to external processors or code generators to the same effect. Anybody who has used them knows how frustrating and difficult to debug they can be. But nonetheless, it's not that people do or don't want syntactic abstractions—they clearly
do—it's more a matter of how accessible we want to make it to the programmer.)
I did not suggest disallowing it anymore than I suggested we should disallow the definition of new classes in Java. Being judicious and deciding when it's worth it is key, and there are few general statements we can make about this without additional context.
I don't disagree with anything you're saying in the abstract, but I'm trying to point out that you were initially responding to someone who had in turn responded to a very specific viewpoint, and the viewpoint you're arguing for seems to be almost the exact opposite of that top-level comment. Someone claimed "XYZ is why I like lisp", and someone else responded "XYZ seems like it might cause issues in practice", and you jumped in to argue back against that by defending Lisp without engaging with the fact that what they were really responding to was XYZ.
The first rule of writing Lisp macros is to not do it if you can get away with using functions. I'd still argue that it requires custom design, but in the same way OOP does. There are established patterns that you know and sometimes iterate on.
It’s going to be used. But at a project and team level rather than at an individual level. You go from lisp, then end up with a DSL that fits the project.
Three thoughts (in the context of Common Lisp specifically):
- Every day that passes, the gulf between Lisp's tooling and what a typical user expects grows wider. It needs to escape Emacs and SLIME to something that feels complete and polished.
- There needs to be a little bit of a culture shift around Lisp to actually write programs that do things. How many programs can you download via apt or brew that are written in Lisp? They're executables at the end of the day so nothing in principle stops this from happening, but there's just a thread of modern Lisp culture where it's more fun to play around in the REPL and write creative libraries than to ship. (There are notable exceptions of course.)
- I personally like the quirkiness of Common Lisp, but there are so many ways to write it (imperative, functional, etc.), so many ways to structure your programs (one package, package per file, package inferred system, etc.), and so many ways to offer APIs (plain old data and functions, generic function protocols, etc.) that it makes it a combination of confusing and intimidating. I think shifting toward something a little more structured and disciplined like Coalton, while still giving the escape hatches to all of Common Lisp, would help a lot of people "join in" on building new code or building upon existing code.
> - Every day that passes, the gulf between Lisp's tooling and what a typical user expects grows wider. It needs to escape Emacs and SLIME to something that feels complete and polished.
Can you give specific examples of "what a typical user expects" that are missing from Emacs-based programming environments (SLIME, and/or others)? I'm not suggesting there aren't any, I'd just like to know your list.
Lisp does not have that much syntax for highlighting to be a problem.
Lisp is also a symbolic language. Meaning the code work on symbols, not data, only at evaluation the value of the symbol is known. There’s a lot of symbols manipulation routines like macros, intern, package loading,… that prevent to statically know the code.
The problem is not a lack of syntax highlighting per se, but the inconsistency of existing syntax highlighting. This is especially annoying in Common Lisp due to the existence of symbol macros, where syntax highlighting would be immensely helpful.
I get that there are issues with symbol manipulation, but AFAIK language servers already evaluate code, even if not for syntax highlighting. I view this whole thing as an issue caused by the REPL workflow, not the inverse. Not to say that I would be willing to give up said workflow but it could certainly use improvements.
- Ease of setup and install. Turnkey. Good defaults.
- Non-buffer based workflows.
- Easy access to settings.
- Easy ways to change or switch my compiler.
- Integrated with typical lisp tooling for library, system, and package management. (For example, what Emacs button do I press to set or clear my ASDF compile cache?)
- Better integration of the profiler and debugger. When a Lisp error happens, yet another buffer pops up (breaking the arrangement of all your code windows you set up), this buffer may not even be the only one (but the others are hidden somewhere), and it's not clear what you can even click or expand to see more information (there's a tremendous amount, extremely non-discoverable).
- Good getting started: built in guide for structural editing, REPL workflow, etc.
...and much much more. I say all of this as someone who basically has only used and invested in Emacs for 20 years. I love sharing Emacs with people who like weird technologies and rabbit holes, the real "hacker"-type people. I hate sharing Emacs with people who want to be productive in an hour or so with a Lisp project, because I know within 5 minutes they'll be disappointed, and never get the best of the experience because it's too much uninteresting investment.
I prefer writing Lisp with Emacs+SLIME over anything else. It's extraordinarily powerful, and with enough grit, you can get it to do almost anything you want. But I'm also jealous of people who get to use, say, polished JetBrains products whose goal is to try to give you the best experience possible for your specific programming language.
JetBrains IDE plugin for Common Lisp: https://github.com/Enerccio/SLT (I'm sure you saw it before and I don't know how polish it is, and I'm pretty sure it has less features than Emacs&SLIME, yet, but I must link it for reference. Because yes, before 2023 we could complain there were no JetBrains IDE plugin for Common Lisp, since 2023, we have one.)
We all can google. Have you tried to install the plugin? It doesn't support the current version of the IDE and as the last commit was 8 months ago there is no hope it will get such a support soon.
TBH no people don't google (what they don't expect to see), repetition and showing links is necessary. I hadn't followed along. Hope it will get contributors.
I mean the following with all due respect—and I have a lot of respect for your many efforts and contributions—but it will sound a little blunt, especially as a written comment.
"We have one," no, this is a consistent problem with people who evangelize Lisp. We have had "IDEs" for decades. Most of them, except the couple commercially supported ones, were "experimental", "incomplete", "buggy", etc. This includes the one you link here.
Are these projects valuable as a starting point for other hackers to join in and help? Sure, maybe. Are they helpful for a new programmer? Almost always the answer has been "no". I have first-hand experience subjecting a programmer to one of these tools, and I myself getting incredibly frustrated at how broken it is. Imagine somebody completely new.
You in particular love to advertise these different projects as a form of Lisp evangelism. Advertising the projects is great—I hope they attract helpers—but I think your language around them is deceiving.
> Because yes, before 2023 we could complain there were no JetBrains IDE plugin for Common Lisp, since 2023, we have one.
"We have one" in the absolutely most rudimentary interpretation of that phrase. What we don't have is a working JetBrains Common Lisp IDE suitable for production use.
In order to try to promote a realistic view as to why Lisp doesn't attract more programmers in 2026, I myself will continue to point out Lisp's highly substandard tooling offering until there's an actual product that works. Any Joe can spend a weekend making a 1/2 baked, proof of concept IDE. Even more so now with all the AI vibecoding tools we have at our disposal. It takes much more to make something that checks all the boxes.
ACK, allright. I just want to point people to stuff. Create emulation. Show that the ecosystem is evolving -in the right direction even, maybe. That we are not doomed to stay with Emacs&SLIME. A few years ago, we didn't have SLIMA, the VSCode plugin, Jupyter and JupyterLite kernels, the very useful ICL, nor CLOG, nor these incomplete IDE attempts (Intellij, Sublime…). How good is the new Zed plugin BTW? https://github.com/etyurkin/zed-cl
(I'm not even evangelizing in these comments so thanks for the feedback I guess!)
Agreed. I think Clojure strikes a pretty reasonable balance here. It's opinionated about the programming paradigm, scales back some of the pain that comes from reader macros, and solves some of the bootstrapping problems by compatibility with other JVM languages.
I love clojure but the points still stand, kind-of.
- There is Calva for VS Code but the community default is emacs and cider
- How many programs in apt or brew are written in clojure? I'd concede that the community is great and focused on productivity, but it's so niche that you don't see much work out there made in clojure, and there is also a vestigial lisp sentiment to prefer building your own library from scratch instead of contributing to a standard library, which spreads the efforts of a small community too much
- Third one you need to mutate it a little bit: clojure is opinionated instead of having "so many ways", but its opinions, while great, are foreign to most programmers
> There is Calva for VS Code but the community default is emacs and cider
Emacs isn’t required. You can always create a REPL plugin. Emacs just does a lot of heavy lifting for you due to comint, sexp navigation, and process management being included.
> building your own library from scratch instead of contributing to a standard library
Simple data structures lead to very generic function. You don’t have to write tower or massive spread of abstractions like in Java or TypeScript. A struct is nothing than a hashmap that can help a typechecker. Most lisp programs prefer primitives or functions instead of manipulating complex objects -never ‘buffer.name’ but ‘(get-buffer-name buffer)’-.
From a module, what you need are functions and an opaque state holder.
With such philosophy, you don’t need a lot of libraries, which are often designed to be complex, when you need a simple model.
> Third one you need to mutate it a little bit
You don’t. Clojure already does the optimization for you for the standard data structures, and they are the only things you need in most cases.
I think this article over-sells (to a point of being misleading) the amount of static type checking offered in Common Lisp even by a relatively good implementation like SBCL.
SBCL's static type checking provides in practice virtually zero guarantees about whether compiling your code actually implies the inexistence of type errors. In that regard, I like to consider SBCL's static type errors to be a mere courtesy [1].
Typically, the static type errors TFA demonstrates are nullified as soon as anything is abstracted away into a function. To show a trivial example:
(+ 2 "2")
may error statically because the Common Lisp implementation has special rules and knowledge about the + function, but
(defun id (x) x)
(+ 2 (id "2"))
will not. Furthermore, Common Lisp has no way to label the type of the function ID to constrain its input type to be the same as its output type that works for all possible types. That is, there's nothing like the Haskell declaration
id :: a -> a
id x = x
or the C++
template <typename A>
A id(A x) {
return x;
}
In Common Lisp, the closest you can get is either to declare ID to be monomorphic (i.e., just select a single type it can work with), as in
(declaim (ftype (function (string) string) id))
or to say that ID can take anything as input and produce anything (possibly different from the input) as output, as in
(declaim (ftype (function (t) t) id))
Here, T is not a type variable, but instead the name of the "top" type, the supertype of all types.
[1] SBCL and CMUCL aren't totally random in what static type checking they perform, and the programmer can absolutely make profitable use of this checking, but you have to be quite knowledgeable of the implementation to know what exactly you can rely on.
I think the criticism is relevant because TFA isn't the first to exercise the term "cognitive load" in the context of computing. It's a term thrown around quite often, so we should cross reference its alleged meaning to literature.
I myself find it to be a term that's effectively used as a thought-terminating cliche, sometimes as a way to defend a critic's preferred coding style and organization.
hmm. Using a term from formal science literature to loosely argue or back questionable arguments withe the ruse of scientific basis is a common issue. I pointed out that this article does not use the formal definition of the term, which you point out is itself an issue. Put that way i agree.
I think the article could have used a different term, or made a more clear declaration of what they specifically meant with the term to resolve this issue. Though i don't think it was done intentionally to deceive since the article makes no mention of the formal literature or theory of "cognitive load" to back its arguments.
S-expressions make the user interface to code generation, a component to hot-reloading, more facile. It's not a triviality or gimmick in this context.
We can see from OP that it's actually quite annoying to specify code in a non-S-expression language (or really any language lacking a meta-syntax), usually requiring either
- stuffing and interpolating strings
- building ASTs with API functions provided by the implementation in a tiresome or verbose manner
But you're right that there are more aspects to hot-reloading than just the syntax and data structure.
Common Lisp gets away with it because it actually defines the semantics of redefinition of functions and classes. For instance, the standard says what will happen to all existing FOO object instances in memory if I change
and even lets the programmer customize the behavior of such a redefinition.
Few if any languages go through the trouble of actually defining these semantics, especially in the context of a compiled language (like Common Lisp), making all but the simplest instances of reloading code well defined.
> ITA Software by Google
Airfare search engine and airline scheduling software. Cambridge, MA. Common Lisp is used for the core flight search engine. The larger Flights project is roughly equal parts CL, C++, and Java.
Read the last sentence AND this company got acquired by Google like 15 years ago. So ya my question still stands.
You asked where Lisp is useful, and I supplied a list of companies that find (or, in some cases of recent history, found) Lisp useful. Your Google example is pertinent, because Google had the resources to wholesale eliminate its use of Lisp any time within the last 15 years, but for some reason worth pondering, hasn't. Instead, they continue to develop the product in Lisp, and continue to contribute to the Common Lisp open-source ecosystem.
But that aside, if you want a fresh look at what people are thinking about with Lisp, maybe check out the talks that were given this year at the 2025 European Lisp Symposium [1,2]. Or perhaps look at how someone shipped a platformer game on Steam with Common Lisp [3,4], and is in the finishing lap porting it to the Nintendo Switch [5].
I realize, though, that this kind of "debate" (?) is never satisfying to the instigator. If it does satisfy though, I will agree with you that—despite all of the claims of alleged productivity and power the language offers—Common Lisp remains far less popular than Python, which I assume is your only real point here.
[1] A presentation about how adding a static type system to Common Lisp à la Haskell helps write mission critical programs in defense and quantum computing: https://youtu.be/of92m4XNgrM
[2] A talk from employees of Keepit, a company that supplies a SaaS backup service, discussed how they train people on Common Lisp when employing them: https://youtu.be/UCxy1tvsjMs?t=66m51s
[4] The actual game that you can buy: https://store.steampowered.com/app/1261430/Kandria/ (This is not intended to be an advertisement and I'm unaffiliated. It's just a demonstration of a recently "shipped" product written in Common Lisp where you might not expect it.)
> Ok now do the part where lisp is actually used for any remotely useful project today...
> So ya my question still stands.
That list has 100 companies using lisp today. Were you actually asking if any new companies write in Lisp? Cuz those exist as well - in the same list...
Not surprising! You didn't make any point you just posted a link to a wikipedia page. Again, sources were posted and you cherry-picked one that still confirmed what you asked about. Nw you're doubling down/moving goalposts. Real companies use lisp, in 2025. It's not that big of a deal.
CLOG [1] seems to do something similar (though it's hard to tell; Seed's README isn't terribly informative), except CLOG has more tutorials, is better documented, has a more fleshed out README, and has ongoing support.
It doesn't make sense in and of itself. We usually think
of division as a closed operation: we divide two things (like real numbers) and we get the same kind of thing out (another real number).
In Hamilton's original view of quaternions, he defined a "geometric quotient" of two 3d directed lines (one kind of object) as being a quaternion (another kind of object), and gave all sorts of complicated geometric formulas for how to calculate it.
reply