May
25
2026

What I would change in Common Lisp

Should the CL standard ever be revised, I would advocate for these two mildly incompatible changes:

1. eval-when

The default compiler policy should be to evaluate each toplevel expression as if it were wrapped in:

(eval-when (:compile-toplevel :load-toplevel :execute) ...)

I can understand the need for this construct, after years of using Lisp and bootstrapping my own compiler, but for a beginner I think the default policy (which is “it depends on the form, see the spec”) can cause unnecessary pain. For somebody coming to CL from any other language, the fact that they can't use a variable or a function immediately in a macro can be surprising and frustrating. Hopefully, they'll Google it and learn the magic spell, and maybe years later, if we're lucky and they're still around, they'll understand why it's needed. Still, they might legitimately think “why is it not the f**king default?

Eval always should be the default, unless explicitely instructed otherwise. In SLip I adopted this policy long ago and I don't intend to change it, although I do intend to implement eval-when at some point.

See also EVAL-WHEN considered harmful to your mental health.

2. Strings should be immutable

… as in pretty much every other high-level language. CL is a high-level language, in that you don't allocate memory manually and you don't mess with pointers like in C (at least per the standard). Now, in every other language, if I pass a string to a function, I would not expect it to be able to alter its contents.

I found a good argument somewhere, but I can't find the link right now. The gist of it was that we tend to think about mutable entities as “containers”, but typically this doesn't apply to strings. Deep down, they do “contain” characters, but every language other than C treats strings as atomic values. And C doesn't really have strings anyway.

Yes, you can retrieve individual characters from a string, pretty much like you can fetch individual bits from an integer; this still doesn't make strings “containers”. Can we say that integers are containers of bits? Deep down they are, especially big integers, which in the genereal case will be heap-allocated. But still, you would not expect a function to be able to change the value of an integer, that wouldn't make sense. If you need a container of bits, you'd use a bit vector.

SLip targets a JavaScript host, so it would be difficult to implement mutable strings. Not impossible, but it would sacrifice performance (which is already scarce) for a very narrow use case. In fact it's not even a use case, it's just a foot-shooting gun. But SLip aside, I can't see a good way to implement mutable strings even when your target is a real CPU. Perhaps it made sense someday when every character was 8 bits, but in today's world it no longer does. Strings should be atomic values, having a dedicated type (not a subtype of VECTOR) and equal strings should be EQL, if not EQ (in SLip they are EQ because there's no way to differentiate between two equal strings, regardless of how they might have been created).

To provide some compatibility, SLip allows SVREF, AREF, LENGTH (etc.) on strings, and some sequence functions do work on strings — but only those that don't mutate the “sequence”.


Dec
10
2025

CopIMAP - IMAP/Maildir library for Common Lisp

In what now seems like a previous life, I wrote a IMAP library for Perl (Net::IMAP::Client). It got somewhat popular and I'm glad to see it's still being maintained — and even more glad that it isn't me who maintains it :)

Around this time last year I wanted to reply to a bunch of emails from Emacs, and had setup OfflineIMAP to download my GMail inbox to a local folder, so that I could use mu4e. While doing so, I checked to see if there's any Common Lisp IMAP client, because OfflineIMAP seemed occasionally slow. Eventually, I thought it would be nice to refresh my memory so I wrote one myself. Maildir syncing is incomplete, but it works for me, so I decided to publish it as is, and announce it here for anyone who follows my website.

More details in the README: https://github.com/mishoo/copimap.lisp


Dec
1
2025

SLip runs QUEEN (Lisp chess library), and a PGN viewer in browser

In the past couple of months I've added some more CL support (some bitwise operators, some multi-dimensional array, and some reader customization), so one day I was able to load my QUEEN chess library and play a bit with it in the browser. It's now included in the build, so you can try this in the REPL:

[ read more... ]


Oct
5
2025

SLip news - more Common Lisp!

SLip is an aspiring Common Lisp environment in the browser.

Since my earlier post in April, I wanted to replace the object system with Closette, as it's more complete than TinyCLOS. Rather than hammering down Closette to fit it into my limited Lisp, I thought I would add sufficient Common Lisp support so that we're able to compile Closette as is, or at least almost. This is the glorious commit where I added Closette with just two tiny changes — I rewrote this function because (at the time) I didn't have typecase, and I removed the :test #'equal from a couple hash tables (I don't support that yet, but it's easy and I'll add it soon). It took some more work from there to actually replace TinyCLOS, but eventually I got it done.

[ read more... ]


Apr
12
2025

SLip — a Lisp system in your browser

I've put some love into my browser-based Lisp system. This project is so old that I could actually say it's new and nobody would know. I just let it rot for something like 12 years, but since I revamped Ymacs recently, I wanted to fix the “IDE”, which was broken; and then I got carried away.

Before reading further, if you are familiar with Common Lisp and Emacs/SLIME, check out this fine REPL! There you'll also find an info file with some information about the environment. And here's the old “crazy clock demo”, which I showcased in a video when I first announced this project.

[ read more... ]


Feb
3
2025

Common Lisp socket client - reconnect on failure

I'm working on an IMAP client for Common Lisp. Details about that in a future post, but I'd like to share here a few bits of code that I had to dig for.

The CL socket tutorials that I could find focus on how to connect to a server, fetch some data and then disconnect. In my case, however, the connection is supposed to be long lived. There's a thread that continuously reads data from the server (it fetches new emails or flag changes and updates a local maildir). Of course, in the wild there is no such thing as a 100% live connection — it will go down for a variety of reasons out of our control, so we need to handle errors and reconnect.

Here is a simplified version of what I came up with. It's probably not perfect, but it works. If you have any ideas for improvements, or if you know some other tutorial about this, please drop me a note!

[ read more... ]


Sep
23
2024

Ymacs: Twig/Django mode and other news

As I find myself writing code in Ymacs sometimes, I wrote a mode suitable for editing Twig/Django templates. It can be enabled with M-x twig_html_mode (the dogfood init code will auto-enable it for buffers coming from web-mode if the filename contains .twig).

While working on this (in itself, of course) I fixed a bunch of other issues related to indentation and syntax highlighting. JS mode will now highlight class, method and function names, and given these changes, I'd like to start working on some imenu-like functionality. Although, to be honest, the current “parsing” system could best be described as “a mess that works”, even after the significant refactoring at the beginning of this year (2024). My efforts would probably be better spent adopting CodeMirror's excellent parser generator (Lezer). But oh well, for now stuff is good enough. 🥲

Here's a small demo with the new Twig mode on:

[ read more... ]


May
31
2024

Carriage return in SLIME output

Here is a small Emacs/SLIME tip, since I couldn't find it on Google and I had to come up with the solution myself. I'm working on a long running Common Lisp program and I print a dot every few thousand iterations, so that I know that something is happening; then every few hundred of thousands I want to replace those dots with some stats about the computation, so I'm writing a carriage return (char code 13) and the stats. On a normal terminal, the whole line of dots will be replaced by the new output, but Emacs just prints ^M and adds the stats on the same line.

Although SLIME seems to be derived from Comint mode, it doesn't use the same code for output (Comint already handles a bunch of caret movement codes, including CR). To make it work in SLIME, paste the following somewhere in your Emacs config (it probably needs SLIME to be already loaded for the advice to work; it is loaded in my case):

;; Interpret #\Return in SLIME output (carriage-return)
(defun my-slime-fix-output (orig-fun &rest args)
  (with-current-buffer (slime-output-buffer)
    (ignore-errors
     (let ((pos (marker-position slime-output-end)))
       (apply orig-fun args)
       (comint-carriage-motion pos (marker-position slime-output-end))))))

(advice-add 'slime-repl-emit :around 'my-slime-fix-output)

May
8
2024

Dogfooding Ymacs

I first learned the term dogfooding at Zimbra in 2005, where we were using the email server and client that we were developing. The internal domain name was dogfood.zimbra.com.

Why would I want to use Ymacs? Its purpose was to enable me to write code in a browser, but in the comfort of my desktop, I can use the real thing. And indeed, Emacs is almost irreplaceable, because it's not just about the editor itself, but the immense ecosystem around it. How can one program in an editor without Magit, for example?

But there are reasons. First, to me, there's this pleasure of using a tool that I created. Then, I'm a strong believer in manual testing — the only way to ensure it's reasonably stable is to actually use it (yes, I'm typing in Ymacs right now). Then, some things might even be better than in Emacs, depending on case and setup — for example I noticed that Emacs with js2-mode (that's what I use) will mismatch quotes of nested template strings. That works properly in Ymacs (including indentation in nested expressions).

I thought that if I could quickly switch between the two, I could use Ymacs for editing work, and go to Emacs for anything else, like Magit. Thus came the idea of a dogfood server — Ymacs would connect to a running Emacs instance, and provide a way to load/save buffers via Emacs. That was pretty easy to write. Yes of course there is a HTTP server for Emacs.

[ read more... ]


Apr
19
2024

Ymacs Reloaded

Hello. Here's an Ymacs update, after 12 years. Remember Ymacs? It's an Emacs-like editor that works in the browser. Here is what's new.

  • Zero dependencies. Ymacs no longer requires my old DynarchLIB toolkit. The minified and gzipped payload is under 50K, which is pretty small by today standards. Along with this change I modernized the code to use ES6 features (e.g. classes, modules), improved theming and added a simple build system based on Parcel.

  • Improved isearch, query-replace. This took a surprising amount of fiddling, but finally, it's Good™. It has “lazy highlighting”, stats (current/count), regexp, word, case folding, lax whitespace. Query-replace is new (old Ymacs didn't have it). Supports similar-case in replacements, regexp replacement variables, bound to selection when active, etc. — with the standard Emacs keybindings, except for C-w 😢 which see below.

[ read more... ]


« Before 19 Apr 2024