Major pain point in SBCL and its implementation of CLOS.

Galen_42 via Sbcl-devel <[email protected]>
Newsgroups gmane.lisp.steel-bank.devel
Message-ID <cwHZyft3U2g-XWKOPLoHrUgMU9ciGU2hSCrjpB0OBYmmpY_1HI9yYaFYLg_aGnTd_IUDZyomBzzwH6vPOPmg1pHl9d9gveiH4FkBcVgClQs=@protonmail.com>
Hello,

I’m writing to propose a change that would eliminate what is, in 2025, still the single largest recurring waste of programmer time in the SBCL ecosystem.

When a class is redefined interactively with DEFCLASS, SBCL deliberately does **not** call FINALIZE-INHERITANCE automatically.
Every other major Common Lisp implementation does it automatically.

The consequence is well-known: every SBCL user who develops with CLOS (and especially with Postmodern, Mito, S-SQL, etc.) must manually add the same boilerplate everywhere:

(eval-when (:compile-toplevel :load-toplevel :execute)
(when (find-class 'foo nil)
(finalize-inheritance (find-class 'foo))))

Postmodern tries to help by calling FINALIZE-INHERITANCE itself inside its DAO-CLASS metaclass.
This sounds good — until you combine the two workarounds.
The result is **double finalization**, often at the wrong time, which triggers a cascade of obscure errors (the infamous “The value NIL is not of type STRING” during slot validation being the most common).
What should be a 10-second class tweak turns into hours of head-scratching, macro-expansion debugging, and package-lock fights — all because two different pieces of code are trying to paper over the same missing SBCL behaviour.

I personally spent an entire day on this exact problem last week.
I have seen dozens of others do the same over the years.
It is the #1 cause of “it works on CCL, why does it explode on SBCL?” questions.

The performance argument no longer holds water in 2025:

- Finalizing a class on a modern machine is measured in microseconds.
- It has zero effect on runtime performance once the class is finalized.
- It can be gated behind interactive evaluation detection (*load-pathname* nil, REPL session, etc.) with nearly zero cost in compiled code.

Proposed solutions (in order of preference)

1. **Best:** automatically finalize on redefinition when evaluated interactively
(detected via *load-pathname* or REPL context)

2. **Excellent:** a global opt-in special variable
(defvar *auto-finalize-on-redefinition* t)

3. **Still helpful:** a per-DEFCLASS declaration

This single change would instantly remove thousands of lines of duplicated, fragile boilerplate from every SBCL codebase that uses DAOs or interactive CLOS development, and — more importantly — stop Postmodern’s well-intentioned workaround from actively interfering with the manual one.

It would save the community hundreds of hours per year with no measurable downside.

It seems to me that a bit of code that detects whether or not the class redefinition is taking place in the compiler or REPL would solve this for everyone with little overhead. Something like this perhaps:

(defmacro defclass (name superclasses slots &rest options)
`(progn
(cl:defclass ,name ,superclasses ,slots ,@options)
;; This branch is compiled away completely in COMPILE-FILE
,(when (and (not *compile-file-truename*)
(not *load-truename*))
`(eval-when (:execute :load-toplevel)
(when (find-class ',name nil) (myapp:create-table ',name))))))

Thank you very much for considering this long-overdue quality-of-life improvement.

Best regards,
Galen

-------------------------------------------------------------------
Never underestimate the power of human stupidity.
- Robert Heinlein

_______________________________________________
Sbcl-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/sbcl-devel
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.