Re: Major pain point in SBCL and its implementation of CLOS.
Richard Westhaver <[email protected]>
| Newsgroups | gmane.lisp.steel-bank.devel |
|---|---|
| Message-ID | <CAOt6oAOZpxT4AF0y8+0M8uvus8GuqsbWfz7NR-=g2G2xQM2Rsg@mail.gmail.com> |
Is it really that common? I haven't ran into it but I don't use Postmodern/the DAO classes. I would assume Pascal's boilerplate avoids the double finalization issue well enough that you wouldn't run into that cascade of errors. On Wed, Dec 3, 2025 at 5:27 PM Galen_42 via Sbcl-devel < [email protected]> wrote: > Pascal, > > I am curious. Why don't you modify DEFCLASS so that it will do the > following: > > > 1. Detect when it is in the REPL. > 2. Determine if it is redefining a class. > 3. 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 > _______________________________________________ Sbcl-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/sbcl-devel