Is there any standard way to create a transient class in CLOS; that is, a class which can be GC'd after all its instances are dead?
In SBCL, I tried (setf test (defclass #:foo () ()))
, i.e. using an uninterned symbol under the assumption that it would normally only be the class' name which caused the class to be retained by the GC, but installing a SBCL finalization function on that class and then setting the symbol value of TEST to NIL shows that the class is never GC'd, no matter how many times I run (gc :full t)
. Which leaves me wondering if it's possible, and if so, how.
It does not matter that the class name, a symbol, is not interned in a package. FIND-CLASS
will find the class by looking at some internal registry data structure. Clozure Common Lisp uses for example a normal hash table CCL::%FIND-CLASSES%
.
There is no standard way. The Common Lisp standard provides no mechanism. Typically a CLOS implementation will want to provide a list of all subclasses of a certain class. For that it needs a reference from a class to its subclasses. It is not specified that this should be a weak reference. For example CLISP implements it as a weak references, other Common Lisp implementations may not.
Sketch of a solution:
So in a finalizer you would need calls to REMOVE-DIRECT-SUBCLASS
(in what package that function may be, often in package CLOS
) to remove the class from its superclasses.
You also need to call (setf (find-class 'my-class-to-be-removed) nil)
.
You also better look that the class does not have subclasses itself.
So you may be able to build something using the widely supported MOP and implementation specific finalizers.