дополнительные свойства к определению слота

http://mop.lisp.se/concepts.html говорит:

Реализация может свободно добавлять дополнительные свойства в спецификацию канонизированного слота при условии, что они не являются символами, доступными в пакете common-lisp-user или экспортируемыми любым пакетом, определенным в стандарте ANSI Common Lisp.

с примером:

(defclass sst (plane)
     ((mach mag-step 2
            locator sst-mach
            locator mach-location
            :reader mach-speed
            :reader mach))
  (:metaclass faster-class)
  (another-option foo bar))

Но когда я пытаюсь:

(defclass a () ((x my-option 123)))

SBCL компилирует его с ошибкой:

Недопустимый аргумент инициализации: MY-OPTION в вызове класса

                SB-MOP:STANDARD-DIRECT-SLOT-DEFINITION>.    

[Условие типа SB-PCL::INITARG-ERROR]

Итак, вопрос. Как я могу добавить дополнительные свойства (например, «my-option») в определение слота?


person user1312837    schedule 24.02.2014    source источник


Ответы (1)


Реализация может сделать это. Но пользователь не может добавлять случайные свойства. Если реализация Common Lisp поддерживает протокол метаобъектов, его можно добавить через собственный метакласс. Но это означает, что нужно также предоставить способы вычисления слотов и т.д.

Это продвинутый Лисп. В книге The Art of the Metaobject Protocol есть пример в главе 3, Расширение языка.

Простой пример (работает в LispWorks):

(defclass foo-meta-class (standard-class) ())

(defclass foo-standard-direct-slot-definition (standard-direct-slot-definition)
  ((foo :initform nil :initarg :foo)))

(defclass foo-standard-effective-slot-definition (standard-effective-slot-definition)
  ((foo :initform nil :initarg :foo)))

(defmethod clos:direct-slot-definition-class ((class foo-meta-class) &rest initargs)
  (find-class 'foo-standard-direct-slot-definition))

(defmethod clos:effective-slot-definition-class ((class foo-meta-class) &rest initargs)
  (find-class 'foo-standard-effective-slot-definition))

Давайте используем его в определяемом пользователем классе:

(defclass foo ()
  ((a :initarg :a :foo :bar))
  (:metaclass foo-meta-class))

В этом случае объект определения слота будет иметь слот foo с содержимым bar.

CL-USER 10 > (find-class 'foo)
#<FOO-META-CLASS FOO 42200995AB>

CL-USER 11 > (class-direct-slots *)
(#<FOO-STANDARD-DIRECT-SLOT-DEFINITION A 42200B4C7B>)

CL-USER 12 > (describe (first *))

#<FOO-STANDARD-DIRECT-SLOT-DEFINITION A 42200B4C7B> is a FOO-STANDARD-DIRECT-SLOT-DEFINITION
FOO                     :BAR
READERS                 NIL
WRITERS                 NIL
NAME                    A
INITFORM                NIL
INITFUNCTION            NIL
TYPE                    T
FLAGS                   1
INITARGS                (:A)
ALLOCATION              :INSTANCE
DOCUMENTATION-SLOT      NIL

Очевидно, что это еще не все, если свойство должно иметь какое-то реальное значение.

person Rainer Joswig    schedule 24.02.2014
comment
Спасибо! Этот пример отлично работает с lispworks. Но с SBCL и close-mop возвращает ошибку: класс #‹STANDARD-CLASS STANDARD-OBJECT› был указан как суперкласс класса #‹FOO-META-CLASS FOO›, но метаклассы #‹ STANDARD-CLASS STANDARD-CLASS› и #‹STANDARD-CLASS FOO-META-CLASS› несовместимы. Определите метод для SB-MOP:VALIDATE-SUPERCLASS, чтобы избежать этой ошибки. [Состояние типа SIMPLE-ERROR] - person user1312837; 25.02.2014
comment
Вам просто нужно сделать именно то, что он говорит: (defmethod validate-superclass ((class foo-meta-class) (superclass standard-class)) t) (документация) - person Philipp Matthias Schäfer; 25.02.2014
comment
@ user1312837: LispWorks нужен validate-superclass только тогда, когда метакласс foo-meta-class НЕ является подклассом standard-class. Что имеет смысл. Для SBCL просто добавьте метод, упомянутый Филиппом. - person Rainer Joswig; 25.02.2014
comment
@RainerJoswig интересно, что, делая это, по крайней мере, в SBCL, я могу получить значение слота foo в прямом определении слота, однако значение foo в эффективном определении слота остается нулевым. Похоже, что форма defclass неправильно инициализирует foo в эффективных слотах. - person spacebat; 30.10.2015
comment
Также подтверждено это в LispWorks personal 6.1.1. Придется порыться в AMOP в поисках подсказок. - person spacebat; 30.10.2015