Re: 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 <rB10ohVel7vBfPzftF2-Qh17FWqWGvPTMnxUPkxrt8BYphj76H12y4Fb-cHorxgAtjX75e1dXnbh3-gXBJcP19hVGNToxGQoVpuFKUK8nBQ=@protonmail.com>
Pascal,

I am curious. Why don't you modify DEFCLASS so that it will do the following:

- Detect when it is in the REPL.
- Determine if it is redefining a class.
- If the first two conditions are true then finalize the class.

This would seem to be a fairly low cost solution to the problem without having to seriously change the design of SBCL.

It would seem to be better for the users, rather than everyone spending time adding ad hoc code to their projects in order to keep their development environment from breaking. Much of the point of using Common Lisp is lost if the REPL keeps locking up for no easily recognized reason.

How many thousands of man-hours of programmer time have been lost due to forgetting or debugging various solutions to this problem over the last twenty years?

Galen

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

On Wednesday, December 3rd, 2025 at 12:46 AM, Pascal Costanza <[email protected]> wrote:

> Hi,
>
> The class finalization protocol does not primarily exist for reasons of performance. To quote the MOP specification, it exists to "support forward-referenced superclasses, and to account for the fact that not all classes are actually instantiated".
>
> The workaround you describe below is not sufficient. You should state something like this:
>
> (let ((class (find-class 'foo nil)))
> (when class
> (unless (class-finalized-p class) ;;; <<<<<
> (finalize-inheritance class))))
>
> Pascal
>
>> On 3 Dec 2025, at 06:02, Galen_42 via Sbcl-devel <[email protected]> wrote:
>
>> 
>> 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

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