Как изменить метакласс класса

Это случается со мной снова и снова: я определяю класс и забываю, что я хотел, чтобы он функционировал, или это, скажем, класс виджета 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 для функций.

person mobiuseng    schedule 07.08.2016    source источник


Ответы (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?

Нет, только сборщик мусора имеет глобальное представление, и по практическим соображениям он обычно не сохраняет обратные ссылки на то, кто ссылается на конкретный объект (и как)1. Нет глобальной записи всех экземпляров класса, если вы не введете свою собственную (слабую) хеш-таблицу для их хранения. Но если вы вели учет всех своих экземпляров, вы можете CHANGE-CLASS их. Например, вы определяете:

(defclass garbage () ())

... любая ранее сохраненная ссылка в вашем объекте будет освобождена, и у GC есть возможность избавиться от объектов, на которые ссылаются ваши экземпляры. И когда другой объект ссылается на экземпляр «мусора», вы можете обновить его. Вместо использования «мусора» вы, вероятно, могли бы изменить экземпляры старых классов на новый класс (имя такое же, но объект класса другой). Также обратите внимание, что CHANGE-CLASS — это общая функция.


1. Реализации могут предлагать средства обхода кучи. См., например, обходчики кучи в Allegro CL.

person coredump    schedule 07.08.2016