Common lisp 如何更改类别';s元类

Common lisp 如何更改类别';s元类,common-lisp,sbcl,clos,Common Lisp,Sbcl,Clos,这种情况一次又一次地发生在我身上:我定义了这个类,但忘记了我希望它是可函数的,或者说它是Gtk widget类,因此需要声明它的元类。但是,一旦定义了元类,SBCL就不允许我更改元类(即使没有此类的实例)。例如,评估 (defclass foo () ((slot-a))) 然后添加一个元类并重新评估: (defclass foo () ((slot-a)) (:metaclass gobject:gobject-class)) 错误结果: Cannot CHANGE-CLASS

这种情况一次又一次地发生在我身上:我定义了这个类,但忘记了我希望它是可函数的,或者说它是Gtk widget类,因此需要声明它的元类。但是,一旦定义了元类,SBCL就不允许我更改元类(即使没有此类的实例)。例如,评估

(defclass foo ()
  ((slot-a)))
然后添加一个元类并重新评估:

(defclass foo ()
  ((slot-a))
  (:metaclass gobject:gobject-class))
错误结果:

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]
不幸的是,我没有一个元对象协议艺术的副本来检查它说了什么。目前,我唯一能找到的方法是重新启动lisp,这可能会造成相当大的破坏

因为我很快就意识到了这个错误,所以我不介意通过删除它来完全避开已定义的类。问题:

  • 如果我已经创建了这个类的实例,有没有办法找到它们使其无效并获得GCed
  • 如何删除该类?类似于函数的
    fmakunbound
不幸的是,我没有一个元对象协议艺术的副本来检查它说了什么

尽管我建议你读这本书,但你可以在网上找到一些信息。例如,见

如何删除该类

您可以使用:

或者,你可以使用花式粘液检测仪。在指向类的名称时调用
slime inspect defination
。然后,您将看到名称。选择它时,将检查命名类的符号。然后,您可以看到如下内容:

It names the class FOO [remove]
如果FOO只命名一个类,您可以使用更大的锤子:

(unintern 'foo)
如果我已经创建了这个类的实例,有没有办法找到它们使其无效并获得GCed

不,只有GC具有全局视图,并且出于实际原因,它通常不会保留关于谁引用特定对象(以及如何引用)的向后引用1。 一个类的所有实例都没有全局记录,除非引入自己的(弱)哈希表来存储它们。但是,如果您保存了所有实例的记录,则可以删除它们。例如,您定义:

(defclass garbage () ())
。。。对象中以前持有的任何引用都将被释放,GC有机会处置引用到您的实例中的对象。当另一个对象引用“垃圾”实例时,您可以更新它。您可以将旧类的实例更改为新类(名称相同,但类对象不同),而不是使用“垃圾”。 还要注意,
CHANGE-CLASS
是一个通用函数


1。实现可能提供堆漫游器。例如,见

(defclass garbage () ())