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”.

No comments yet. Wanna add one? Please?

Add your comment

May
25
2026

What I would change in Common Lisp

  • Published: 2026-05-25
  • Modified: 2026-05-25 19:36
  • By: Mishoo
  • Tags: lisp, common lisp
  • Comments: 0 (add)