functions – ¿Puede un símbolo tener una función, una variable y una clase?

Pregunta:

P: ¿ Puede un símbolo referirse a una función, una variable y una clase?

Elisp es un Lisp-2 en el que un símbolo puede tener valores de función y variable separados. Entonces, por ejemplo, puedo definir la siguiente función y variable:

(defun kittens ()
  "Profess love of kittens."
  (message "I love kittens!"))

(defvar kittens nil
  "A variable to store information about kittens.")

Y consulta sus respectivos contenidos:

(symbol-value 'kittens)       ; => nil
(symbol-function 'kittens)    ; => (lambda nil "Profess love...")

Sin embargo, una vez que defino una clase con el mismo nombre:

(defclass kittens ()
  ((quantity
    :initarg :quantity
    :initform 1000
    :accessor kittens-quantity
    :documentation "How many kittens anyone should strive to own."))
  "Kitten class.")

La clase parece reemplazar la función y la variable:

(symbol-value 'kittens)       ; => kittens
(symbol-function 'kittens)    ; => (lambda (&rest slots) "Create a new object...")

Entonces: ¿las clases simplemente golpean la función y la variable originales, o los valores originales todavía existen en alguna parte?

Respuesta:

La respuesta corta es no.

Una vez que declare una clase, Emacs definirá una función con el nombre de esa clase como función de creación, reemplazando así su antigua definición de función. En Emacs, eieio.el tiene una macro para defclass que dice así:

(defmacro defclass (name superclasses slots &rest options-and-doc)

  ;; A lot of stuff here...

  ;; Non-abstract classes need a constructor.
  `(defun ,name (&rest slots)
     ,(format "Create a new object of class type `%S'." name)
     (declare (compiler-macro
               (lambda (whole)
                 (if (not (stringp (car slots)))
                     whole
                   (macroexp--warn-and-return
                    (format "Obsolete name arg %S to constructor %S"
                            (car slots) (car whole))
                    ;; Keep the name arg, for backward compatibility,
                    ;; but hide it so we don't trigger indefinitely.
                    `(,(car whole) (identity ,(car slots))
                      ,@(cdr slots)))))))
     (apply #'make-instance ',name slots))

Tenga en cuenta que la macro se ejecuta (defun kittens (&rest slots) ...

Debe tenerse en cuenta que la variable eieio-backward-compatibility (predeterminada en t ) controla si tus kittens siguen una variable después de defclass .

Por ejemplo, cuando defino puppies sin compatibilidad con versiones anteriores:

(setq-local eieio-backward-compatibility nil)

(defclass puppies ()
  ((quantity
    :initarg :quantity
    :initform 1000
    :accessor puppies-quantity
    :documentation "How many puppies anyone should strive to own."))
  "Puppies class!")

(symbol-function 'puppies)    ; => (lambda (&rest slots) "Create a new object...")
(symbol-value 'puppies)       ; => error: (void-variable puppies)

La función aún se sobrescribirá, pero si tiene un conjunto de variables, puede permanecer.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top

web tasarım