The Light Side is about preventing the programmer from making mistakes: Get rid of go-tos! Add static types! Do not allow a bug to be expressible. The Dark Side is about giving power to the programmer: Macros? Obviously. Operator overloading? Self-modifying code? Multi-line reg-exps? Go to town!
The Light Side knows programmers are flawed and imposes constraints. The Dark Side trusts programmers with power. Neither side is correct all of the time, and a good programmer learns both.
Lisp is interesting in that it is clearly Dark Side programming (the programmer can do anything) but it's still admired by Light Side programmers. Maybe there's something about the simplicity of the language that makes it seem platonic--almost incorruptible. Or maybe Lisp is so pure that it embodies both Light Side and Dark Side, like a god that spawned the programming universe.
Mine: a complete, single-download application that comes with everything needed to experience the interactive and incremental development programming workflow, including hot-reloading and on-the-fly debugging. For CL and Coalton.
https://coalton-lang.github.io/20260424-mine/
OLIVE: a new hand-made plugin for VSCode.
ICL: a new REPL for the terminal and the browser with advanced features.
as a bonus: a JupyterLite kernel based on JSCL that runs 100% in the browser.
find them all: https://lispcookbook.github.io/cl-cookbook/editor-support.ht...
Articles like this, and the PG articles it references, amount to "if you know, you know". I understand the appeal and I understand the explicit and implicit arguments this article is making.
Computer programming has matured quite a bit in the past 60 years. I would like to see more articles that are more considered in their examination.
I always thought that the "answer" to programming would be that one day everyone would use Lisp and with awesome tooling and libraries things would be wonderful. In fact, my plan for retirement was to build high-quality libraries for a Lisp language to accelerate this process.
Does the rise of AI bring an end to this dream? Is that, once again, we have solved the problem by adding more cruft? Rather than a superintelligent AI writing in the best programming language available, we're going to just spam lots of Python code until it works?
Does this matter? I don't know, I just wanted a world of elegance.
Now I think the best programming language is Barry Jay's Triage Calculus, which is close to combinatory logic or untyped lambda calculus.
But unlike lambda calculus (which is easily expressed in TC), triage calculus has a built-in quoting and introspection (similar to Lisp's CAR and CDR), which lets you easily add typechecking. So in TC, you can have any syntax you want, just by building the correct abstraction. It's truly an ultimate programming language.
TC shows that there is a false dichotomy between programming language features and syntax on one hand, and the function/API definitions in the standard library or user code on the other hand. Every time you write a piece of code intended to be reusable, you're adding to the language. It can all be expressed as some term in TC.
All the syntactic squibbles are a matter of habit. Although one syntactic feature you really want in TC is the let over lambda abstraction, because it's somewhat annoying to order combinators by hand.
I looked at lisp many times and it just doesn't do it for me.
It uses python for the interpreter.
The one part I can’t imagine is how do you pass a Lisp function as a callback?
Maybe I just don't know where to start.
I never managed to get over the ().
Ruby has a very flexible syntax, compared to many other languages, in that you can omit syntax in many cases. For instance, using () for method calls is largely, for the most part, optional. So when I have the python code:
cat = Cat()
cat.meow()
I find it worse than the ruby code: cat = Cat.new
cat.meow
(Though you can use () in ruby there too; but most people
won't do so as there is little point in that.)This is a superficial issue though. Python's biggest mistake is to require implicit self. It always feels as if I need to hand-hold python and trying to explain to it what an object is and what self is. In ruby I don't have that issue. Note that I find both languages fine, but ruby is "more" object oriented than python is, for many reasons.
Lisp is quite different though. I had some exposure to it via scheme and while it can be fun, I feel that lisp is a worse programming language than either ruby or python. The old game haxima/nazghul was given up eventually, primarily due to lack of time, but also because the author was no longer convinced of scheme (the core of the engine is in C if I recall correctly). He tried to switch to python, though, which did not work (but, again, I think it was mostly due to lack of time). The scheme code in haxima/nazghul was quite interesting (https://sourceforge.net/projects/nazghul/ if you want to look at the scheme code there), but I much prefer either ruby or python there. Although it would be interesting to have DSLs that would really focus on the game or project at hand, like in the old Zak McKracken game.
> [...] among its extensibility, its interactive environment, the REPL, and a lot of other features we haven’t touched yet. It is the combination of all of them that makes Lisp programming what it is.
Agreed. However, although the alternatives are few, they do exist. Today, I'd like to convince you (whether you're OP or a commenter) to give one of them a try. I'm talking about GToolkit[1]: Smalltalk/Pharo-based reimagining of Smalltalk as a productive environment for modern system design, analysis, and implementation. It's based on Pharo and its VM, but with GT-specific extensions and replacements, developed on GitHub in both Smalltalk and Rust.
I used both Common Lisp and Smalltalk over the years for some of my side projects. Technically, the environments are comparable: image-based, live, interactive development is central to both. Lisp is easier to fit into modern workflows: it's still just files on disk. If you ignore the REPL and treat the image as a bundler, you can have a Java- or Python-like development workflow. You can gradually adopt the more interactive ways of working with the codebase. Smalltalk was historically more of an "all or nothing" approach, but nowadays it supports Git-based workflows as first-class, with GToolkit providing additional tools directly. GT is tied to a single IDE, but that IDE is genuinely powerful, pragmatic, and easy to customize: the entire IDE is Smalltalk code[2] that lives in the image beside your code, so you can live-edit any part of it at any time.
The languages differ, most obviously in the object model (single inheritance and message sends in Smalltalk, and multiple inheritance with multimethods in CLOS), but I don't think one is strictly better than the other for the vast majority of code. You just need to structure your code differently. Both systems are very dynamic, so neither is like Java or C++. After quite a few projects in both, I am convinced that this difference doesn't matter.
Both languages have very simple syntax. Smalltalk doesn't have macros; instead, it has an extensible/replaceable compiler for method bodies. This capability is used, for example, for compiling grammars into parsers/lexers in SmaCC. It's not as convenient for control-flow abstraction as CL's macros, but Smalltalk tends to make them out of blocks (lexical closures with non-local exits) plus actions on thisContext. In practice, I never found either language too limiting in what I could express, and both have small, regular basic syntax.
TL;DR: Common Lisp and GToolkit Smalltalk offer comparable technical merits, with the most pronounced difference being GT's built-in, high-quality IDE, which open source Lisp lacks.
The IDE (and the capability to build cross-platform, but natively rendered GUI apps) is the major selling point of GToolkit, but the bigger reason to consider it is social. Lisp had a bit of a renaissance from 2005 to 2015, but ~it has since died down~ (EDIT: After checking a bit, it's more like there are similar levels of development now, but it's just varied, and I personally hit a few areas where nothing new happened for a while. Or in other words, the hopes of CL getting catapulted to mainstream by the wave of adoption didn't materialize, and the adoption seems to have largely plateaued, with a slight upward trend since then.) A lot of great things for Lisp appeared in that time: ASDF and Quicklisp being prime examples. Unfortunately, the momentum was lost, and since then, the rate of development has plummeted. It's still a solid proposition because of its stability, which means a lot of old code still works perfectly well, but it's a double-edged sword: it would take a hundred miracles in a row for CL to get a plausible M:N concurrency story, for example. This isn't true for Smalltalk, and doubly so.
There's a small but active community around Pharo, mostly academics and hobbyists (IME; and it's from a decade ago, so YMMV). Pharo itself is already a "Smalltalk-like" language, and it regularly gets features that are not in original Smalltalk (stateful traits and slots (reification of class and instance variables) are good examples). It continues to evolve, and each version brings notable improvements to the language, the VM, and the class library. In CL, since there are many implementations maintained by various groups and the standard is set in stone, adopting extensions to the standard is incredibly hard and time-consuming. You can, of course, commit to a single implementation, but there are only 2 or 3 implementations that are actively developed and trying to do something "new"; they are all experimental and incomplete. And while SBCL has quite a few nice features, its codebase was a bit hard for me to grok (read: days on end of banging my head against a wall, then giving up; I'm much more comfortable messing with Smalltalk bytecode compiler).
Secondly, GToolkit is driven by a group of coders[3] who have established a profitable consultancy. It's being developed around a single vision that the authors swear helps them achieve their projects' goals. Even if you're not sold on moldable development[4] as a methodology, GToolkit gives you all the tools you might need in a modern development and then adds tons of domain-specific tools and utilities that might be useful after just a bit of adjustment. The whole environment is built to make such adjustments as painless as possible, too.
The only problem I experience with GToolkit is the lack of structured, book-like documentation. The GToolkit book is closer to the PHP wiki or a bundle of tutorials than something like the Rust book. It's not that the docs aren't there - they often are, but finding them effectively is a bit challenging. I found that simply cloning all the repos that GT consists of (tens, if not hundreds, but there's automation for that) and pointing an agent to the directory with them is often enough to quickly find what I'm looking for (if the built-in Spotter fails and I'm too lazy to construct an in-image search).
TL;DR: GToolkit/Pharo move much faster than the CL world, and while the number of maintainers might be similar (honestly hard to estimate, though), the effort on the GT side is more centralized and, in my opinion, heads in a better direction. If you want an extensible, live, dynamic environment that shares many of Common Lisp's strengths, but is more polished, more actively maintained, and feels more modern, take a look at GToolkit.
(Disclaimer: no affiliation, just a programmer who likes to explore unpopular languages).
[2] Some parts are implemented as Rust dynamic libraries and called from Smalltalk via FFI.
My weird take is that lisp would have a better shot if one would replace the parentheses with square brackets. It might just be me but the round parenthesis make it visually painful to look at code blocks. I feel square brackets would fix that.
But ... somehow almost everyone simply ignores this propaganda --- that's actually the way we ought to handle propaganda! Funny that it works with Lisp, but not with many political topics where it can be shown that propaganda really works.
My experience with Lisp is somewhat special-cornered. I only know Emacs-Lisp, and that not great. And for me, Lisp an out, outdated and confusing thing.
I don't know ANY other programming language that elected assembler mnemonics to be "high"-level expression: car and cdr.
While I love Emacs, they claim all the time that is has 100% discovery through build in doc. But that is only 70% true. It doesn't exist in Lisp like it does in other languages. For example, I have an association list. Now, what functions exist that uses them? I can't use the equivalent for (dir alist), alist.dir(), or use some LSP for that. I can't even look in the symbols, because operators are written like assoc or assq with not logic. And then there are either prefixes to them (rassoc) or postfixes (assoc-string).
That there is no namespace is soooo 1970. I mean, even Turbo-Pascal had namespaces.
Typechecking is nonexistant.
At least we have byte-compiling.
And note that I don't croak about the parenthesis. While I find it mildy weird that I as a human program in almost-AST, Emacs has superp support for the parenthesis. So people croaking about them just had never had a good editor IMHO.
Now, one can argue that Emacs Lisp != Common Lisp. But these propaganda articles don't tend to promote one specific Lisp, they only talk in generals. So I can apply this general principle and compare it to the tiny corner of these awful language family.