Как изменить метакласс класса
Это происходит со мной снова и снова: я определяю класс и забываю, что хотел, чтобы он был функциональным или, скажем, классом виджетов Gtk, поэтому необходимо указать его метакласс. Однако, как только он определен, 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
для функций.
1 ответ
К сожалению, у меня нет копии протокола "Искусство метаобъекта", чтобы проверить, что он говорит.
Несмотря на то, что я рекомендую прочитать книгу, вы можете найти некоторую информацию в Интернете. Смотри например ENSURE-CLASS-USING-CLASS
,
Как убрать класс?
Ты можешь использовать (SETF FIND-CLASS)
:
(setf (find-class 'foo) nil)
Или вы можете использовать инспектора фантазии слизи. Ты звонишь slime-inspect-defintion
указывая название класса. Затем вы увидите имя. Когда вы выбираете его, вы проверяете символ, обозначающий ваш класс. Затем вы можете увидеть что-то вроде:
It names the class FOO [remove]
При условии, что FOO только называет класс, вы можете использовать больший молот:
(unintern 'foo)
Если я создал экземпляры класса, есть ли способ найти их, чтобы аннулировать их и получить их GCed?
Нет, только GC имеет глобальное представление, и по практическим причинам оно обычно не хранит обратных ссылок о том, кто ссылается на конкретный объект (и как) 1. Глобальных записей всех экземпляров класса не существует, если вы не введете собственную (слабую) хеш-таблицу для их хранения. Но если вы вели учет всех ваших экземпляров, вы можете CHANGE-CLASS
их. Например, вы определяете:
(defclass garbage () ())
... любая ранее сохраненная ссылка в вашем объекте будет освобождена, и GC будет иметь возможность распоряжаться объектами, на которые ваши экземпляры ссылаются. И когда другой объект ссылается на экземпляр мусора, вы можете обновить его. Вместо использования мусора, вы, возможно, могли бы заменить экземпляры старых классов на новый (имя то же самое, но объект класса другой). Обратите внимание, что CHANGE-CLASS
это общая функция.
1 Реализации могут предлагать кучу ходоков. Смотрите, например, Кучи ходунки в Аллегро CL.