This happens to me time and again: I define the class and forget that I wanted it funcallable or it is, say, Gtk widget class, thus it's metaclass needs to be stated. Once it is defined, however, SBCL doesn't let me change me the metaclass (even if there is no instance of this class). For example, evaluating
(defclass foo ()
((slot-a)))
and then adding a metaclass and re-evaluating:
(defclass foo ()
((slot-a))
(:metaclass gobject:gobject-class))
results in error:
Cannot CHANGE-CLASS objects into CLASS metaobjects.
[Condition of type SB-PCL::METAOBJECT-INITIALIZATION-VIOLATION]
See also:
The Art of the Metaobject Protocol, CLASS [:initialization]
Unfortunately I don't have a copy of The Art of the Metaobject Protocol to check what it says. For now the only way I could figure out is to restart lisp, which can be quite disruptive.
Since I realise the error soon enough, I don't mind dodging the defined class completely by removing it. Questions:
fmakunbound
for functions.The metaclass is determined by looking at the baseclasses of the class-to-be (metaclasses are inherited), at the __metaclass__ attribute of the class-to-be (if any) or the __metaclass__ global variable. The metaclass is then called with the name, bases and attributes of the class to instantiate it.
When defining a class and no metaclass is defined the default type metaclass will be used. If a metaclass is given and it is not an instance of type() , then it is used directly as the metaclass.
In object-oriented programming, a metaclass is a class whose instances are classes. Just as an ordinary class defines the behavior of certain objects, a metaclass defines the behavior of certain classes and their instances.
The __init_subclass__ class method is called when the class itself is being constructed. It gets passed the cls and can make modifications to it. Here's the pattern I used: class AsyncInject: def __init_subclass__(cls, **kwargs): super().
Unfortunately I don't have a copy of The Art of the Metaobject Protocol to check what it says.
Even though I recommend reading the book, you can find some information online. See for example ENSURE-CLASS-USING-CLASS
.
How to remove the class?
You can use (SETF FIND-CLASS)
:
(setf (find-class 'foo) nil)
Or, you can use the fancy slime inspector. You call slime-inspect-defintion
while pointing the name of the class. Then, you'll see the name. When you select it, you inspect the symbol naming your class. Then, you can see something like:
It names the class FOO [remove]
Provided FOO only names a class, you can use the bigger hammer:
(unintern 'foo)
If I have created instances of the class, is there a way to find them to nullify them and get them GCed?
No, only the GC has the global view, and for practical reasons, it doesn't generally keep backward references about who references a particular object (and how)1.
There is no global record of all instances of a class unless you introduce your own (weak) hash-table to store them. But if you have kept a record of all of your instances, you can CHANGE-CLASS
them. For example, you define:
(defclass garbage () ())
... any previously held reference in your object will be released and the GC has an opportunity to dispose of objects your instances where referencing. And when another object reference an instance of 'garbage, you can update it. Instead of using 'garbage, you could probably change instances of old classes to your new class (the name is the same, but the class object is different).
Note also that CHANGE-CLASS
is a generic function.
1. Implementations might offer heap walkers. See for example Heap walkers in Allegro CL.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With