ARNESI

Defining classes with DEFSTRUCT's syntax 

(defmacro defclass-struct (name-and-options supers &rest slots)
  "DEFCLASS with a DEFSTRUCT api.

NAME-AND-OPTIONS:

  name-symbol |
  ( name-symbol [ (:conc-name conc-name ) ]
                [ (:predicate predicate-name ) ] )

SUPERS - a list of super classes passed directly to DEFCLASS.

SLOTS - a list of slot forms:

  name |
  ( name [ init-arg ] [ slot-options* ] )"
  (generate-defclass (first (ensure-list name-and-options))
                     (cdr (ensure-list name-and-options))
                     supers slots))
(defun generate-defclass (class-name class-options supers slots)
  (let ((conc-name nil)
        (predicate nil)
        (predicate-forms nil))
    (loop
       for (option-name . args) in class-options
       do (ecase option-name
            (:conc-name
             (when conc-name
               (error "Can't specify the :CONC-NAME argument more than once."))
             (setf conc-name (first args)))
            (:predicate
             (when predicate
               (error "Can't specify the :PREDICATE argument more than once."))
             (setf predicate (if (eql t (first args))
                                 (intern (strcat class-name :-p)
                                         class-name)
                                 (first args))))))
    (setf slots
          (mapcar
           (lambda (slot-spec)
             (destructuring-bind (name
                                  &optional initform
                                  &rest options)
                 (ensure-list slot-spec)
               `(,name
                 :initform ,initform
                 ,@(when conc-name
                     `(:accessor ,(intern (strcat conc-name name)
                                          (symbol-package conc-name))))
                 :initarg ,(intern (symbol-name name) :keyword)
                 ,@options)))
           slots)
          predicate-forms
          (if predicate
              (with-unique-names (obj)
                `((defmethod ,predicate ((,obj ,class-name)) t)
                  (defmethod ,predicate ((,obj t)) nil)))
              nil))
    `(prog1
         (defclass ,class-name ,supers ,slots)
       ,@predicate-forms)))