From: Daniel Pitts
Subject: defmacro (or other solution) to override default slot definition in defclass...
Date: 
Message-ID: <spSdnd7gFeAlO5TanZ2dnUVZ_judnZ2d@wavecable.com>
I'm trying to create a macro that lets me set up some standard slots in 
a class. The goal is that all of these special slots (I call properties) 
have the specified name, and the specific initarg/reader/writer.
This is my attempt:

(defmacro property (name &rest extra)
         `(,name
         :initarg ,name
         :reader (make-symbol (concatenate 'string (symbol-name ,name) 
"-OF"))
         :writer (make-symbol (concatenate 'string "SET-" (symbol-name 
,name)))
         ,@extra)
)
(defclass thing () (
         (property name)
     )
)

But it looks like defclass is getting the list (property name), instead 
of the macro expansion. Is there a way to force (property name) to be 
expanded before defclass?
Is there a better way to do what I'm trying to do? This is my first Lisp 
experience, so if I'm not going about this the "lisp" way, feel free to 
tell me.

Thanks,
Daniel.
-- 
Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>

From: Rainer Joswig
Subject: Re: defmacro (or other solution) to override default slot definition in defclass...
Date: 
Message-ID: <joswig-07F3D8.05581308102007@news-europe.giganews.com>
In article <································@wavecable.com>,
 Daniel Pitts <····················@virtualinfinity.net> wrote:

> I'm trying to create a macro that lets me set up some standard slots in 
> a class. The goal is that all of these special slots (I call properties) 
> have the specified name, and the specific initarg/reader/writer.
> This is my attempt:
> 
> (defmacro property (name &rest extra)
>          `(,name
>          :initarg ,name
>          :reader (make-symbol (concatenate 'string (symbol-name ,name) 
> "-OF"))
>          :writer (make-symbol (concatenate 'string "SET-" (symbol-name 
> ,name)))
>          ,@extra)
> )
> (defclass thing () (
>          (property name)
>      )
> )

This does not work. Check out the syntax of DEFCLASS in the
HyperSpec.

You could use the read eval feature to create the list
for describing the slot.


(defun property (name &rest extra)
  `(,name
    :initarg ,name
    :reader ,(intern (concatenate 'string (symbol-name name) "-OF"))
    :writer ,(intern (concatenate 'string "SET-" (symbol-name name)))
    ,@extra))


(defclass thing ()
  (#.(property 'name)))


Note that :initarg symbols usually are keyword symbols (:name instead
name).

You might also want to standard Common Lisp indenting soon. The
editor should be able to help.
Parentheses are usually not alone on lines. This wastes
whitespace.

> But it looks like defclass is getting the list (property name), instead 
> of the macro expansion. Is there a way to force (property name) to be 
> expanded before defclass?
> Is there a better way to do what I'm trying to do? This is my first Lisp 
> experience, so if I'm not going about this the "lisp" way, feel free to 
> tell me.

I would write a class for it:

(defclass named-mixin ()
  ((name :initarg :name :accessor name-of)))

(defclass thing (named-mixin) ())

-- 
http://lispm.dyndns.org
From: Daniel Pitts
Subject: Re: defmacro (or other solution) to override default slot definition in defclass...
Date: 
Message-ID: <7oednR6_zbtXLJTanZ2dnUVZ_sytnZ2d@wavecable.com>
Rainer Joswig wrote:
> In article <································@wavecable.com>,
>  Daniel Pitts <····················@virtualinfinity.net> wrote:
> 
>> I'm trying to create a macro that lets me set up some standard slots in 
>> a class. The goal is that all of these special slots (I call properties) 
>> have the specified name, and the specific initarg/reader/writer.
>> This is my attempt:
>>
>> (defmacro property (name &rest extra)
>>          `(,name
>>          :initarg ,name
>>          :reader (make-symbol (concatenate 'string (symbol-name ,name) 
>> "-OF"))
>>          :writer (make-symbol (concatenate 'string "SET-" (symbol-name 
>> ,name)))
>>          ,@extra)
>> )
>> (defclass thing () (
>>          (property name)
>>      )
>> )
> 
> This does not work. Check out the syntax of DEFCLASS in the
> HyperSpec.
I'll check it out.
> 
> You could use the read eval feature to create the list
> for describing the slot.
> 
> 
> (defun property (name &rest extra)
>   `(,name
>     :initarg ,name
>     :reader ,(intern (concatenate 'string (symbol-name name) "-OF"))
>     :writer ,(intern (concatenate 'string "SET-" (symbol-name name)))
>     ,@extra))
> 
> 
> (defclass thing ()
>   (#.(property 'name)))
I think the #. is what I was looking for.
> 
> 
> Note that :initarg symbols usually are keyword symbols (:name instead
> name).
Ah, that's what I meant to have.
> 
> You might also want to standard Common Lisp indenting soon. The
> editor should be able to help.
> Parentheses are usually not alone on lines. This wastes
> whitespace.
I use VIM, because thats what I'm familiar with.  I'm used to Java/C++ 
syntax where the convention is the close blocks on the next line.  Is 
there something I can read on conventional indentation for CL?
> 
>> But it looks like defclass is getting the list (property name), instead 
>> of the macro expansion. Is there a way to force (property name) to be 
>> expanded before defclass?
>> Is there a better way to do what I'm trying to do? This is my first Lisp 
>> experience, so if I'm not going about this the "lisp" way, feel free to 
>> tell me.
> 
> I would write a class for it:
> 
> (defclass named-mixin ()
>   ((name :initarg :name :accessor name-of)))
> 
> (defclass thing (named-mixin) ())
> 
That would be great, except what I'm actually trying to do is create 
thing that has the "property" called "name", and a property called 
"visualization", and a property called "something-else", etc...  See, 
"thing" is really my base class which has a lot of default properties. 
subclasses will have more properties, and other more specific classes 
will have more properties.  The convention for those properties will 
usually be the same, so I was hoping that a macro would help.

Thanks,
Daniel.
-- 
Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>
From: Rainer Joswig
Subject: Re: defmacro (or other solution) to override default slot definition in defclass...
Date: 
Message-ID: <joswig-B55E19.10132508102007@news-europe.giganews.com>
In article <································@wavecable.com>,
 Daniel Pitts <····················@virtualinfinity.net> wrote:

> > You might also want to standard Common Lisp indenting soon. The
> > editor should be able to help.
> > Parentheses are usually not alone on lines. This wastes
> > whitespace.
> I use VIM, because thats what I'm familiar with.  I'm used to Java/C++ 
> syntax where the convention is the close blocks on the next line.  Is 
> there something I can read on conventional indentation for CL?

For example here:

http://dept-info.labri.fr/~strandh/Teaching/MTP/Common/Strandh-Tutorial/indentation.html

> > 
> >> But it looks like defclass is getting the list (property name), instead 
> >> of the macro expansion. Is there a way to force (property name) to be 
> >> expanded before defclass?
> >> Is there a better way to do what I'm trying to do? This is my first Lisp 
> >> experience, so if I'm not going about this the "lisp" way, feel free to 
> >> tell me.
> > 
> > I would write a class for it:
> > 
> > (defclass named-mixin ()
> >   ((name :initarg :name :accessor name-of)))
> > 
> > (defclass thing (named-mixin) ())
> > 
> That would be great, except what I'm actually trying to do is create 
> thing that has the "property" called "name", and a property called 
> "visualization", and a property called "something-else", etc...  See, 
> "thing" is really my base class which has a lot of default properties. 
> subclasses will have more properties, and other more specific classes 
> will have more properties.  The convention for those properties will 
> usually be the same, so I was hoping that a macro would help.

There are several ways to deal with that:

* see the use of read macros already mentioned       (rare)
* write it all out                                   (often)
* use the help of an editor (template, copy/paste)   (often)
* use a specialized version of DEFCLASS              (rare)

DEFCLASS is verbose. I guess it is best handled on the editor
level.

The advantage of the verbosity is that you have to think
about each slot option. Do you really need an initarg
for this slot? An initform? An accessor? What is the
type of this slot? How about a documentation string?

> 
> Thanks,
> Daniel.

-- 
http://lispm.dyndns.org
From: Ken Tilton
Subject: Re: defmacro (or other solution) to override default slot definition in defclass...
Date: 
Message-ID: <9gnOi.527$gM.204@newsfe12.lga>
Daniel Pitts wrote:
> I'm trying to create a macro that lets me set up some standard slots in 
> a class. The goal is that all of these special slots (I call properties) 
> have the specified name, and the specific initarg/reader/writer.
> This is my attempt:
> 
> (defmacro property (name &rest extra)
>         `(,name
>         :initarg ,name
>         :reader (make-symbol (concatenate 'string (symbol-name ,name) 
> "-OF"))

<yawn> verbose.

>         :writer (make-symbol (concatenate 'string "SET-" (symbol-name 
> ,name)))

<ugh> I like SETF.

>         ,@extra)
> )
> (defclass thing () (
>         (property name)
>     )
> )
> 
> But it looks like defclass is getting the list (property name), instead 
> of the macro expansion. Is there a way to force (property name) to be 
> expanded before defclass?

defclass itself is a macro and it chooses to parse slot definitions, not 
evaluate them, so.... no.

> Is there a better way to do what I'm trying to do? This is my first Lisp 
> experience, so if I'm not going about this the "lisp" way, feel free to 
> tell me.

Just write your own macro defklass that does whatever you want to make 
that godawful macro easier to program. defklass will expand into 
defclass and let that do all the standard work. Here is my defmd which 
expands into defmodel which expands into defclass. I think you can just 
change it to expand into defclass and then take out all the cells stuff.

You can say:

(defmd klass ()
    one
    (two 2)
    (three :initform 3 :accessor four))

And get..hang on...

(defmodel klass (model)
    ((one :initform nil :initarg :one :accessor one)
     (two :initarg :two :initform 2 :accessor two)
     (three :initarg :three :initform 3 :accessor four))
    (:default-initargs))

That last (:default-initargs) bit is because AllegroCL's defclass is 
broken, and that is the fix. The defmodel/model is for my own purposes 
in re cells, you would want to expand to defclass and ().

Repairing line breaks left as an exercise:

(defmacro defmd (class superclasses &rest mdspec)
   `(defmodel ,class (,@superclasses model)
      ,@(let (definitargs class-options slots)
          (loop with skip
              for (spec next) on mdspec
              if skip
              do (setf skip nil)
              else do (etypecase spec
                        (cons
                         (cond
                          ((keywordp (car spec))
                           (assert (find (car spec) '(:documentation 
:metaclass)))
                           (push spec class-options))
                          ((find (cadr spec) '(:initarg :type :ps 
:persistable :cell :initform :allocation :reader :writer :accessor 
:documentation))
                           (push (apply 'defmd-canonicalize-slot spec) 
slots))
                          (t ;; shortform (slotname initform &rest 
slotdef-key-values)
                           (push (apply 'defmd-canonicalize-slot
                                   (list* (car spec) :initform (cadr 
spec) (cddr spec))) slots))))
                        (keyword
                         (setf definitargs (append definitargs (list 
spec next)))
                         (setf skip t))
                        (symbol (push (list spec :initform nil
                                        :initarg (intern (symbol-name 
spec) :keyword)
                                        :accessor spec) slots)))
              finally
                (return (list* (nreverse slots)
                          (delete nil
                            (list* `(:default-initargs ,@definitargs)
                              (nreverse class-options)))))))))

(defun defmd-canonicalize-slot (slotname
                                 &key
                                 (cell nil cell-p)
                                 (ps t ps-p)
                                 (persistable t persistable-p)
                                 (owning nil owning-p)
                                 (type nil type-p)
                                 (initform nil initform-p)
                                 (initarg (intern (symbol-name slotname) 
:keyword))
                                 (documentation nil documentation-p)
                                 (unchanged-if nil unchanged-if-p)
                                 (reader slotname reader-p)
                                 (writer `(setf ,slotname) writer-p)
                                 (accessor slotname accessor-p)
                                 (allocation nil allocation-p))
   (list* slotname :initarg initarg
     (append
      (when cell-p (list :cell cell))
      (when ps-p (list :ps ps))
      (when persistable-p (list :persistable persistable))
      (when owning-p (list :owning owning))
      (when type-p (list :type type))
      (when initform-p (list :initform initform))
      (when unchanged-if-p (list :unchanged-if unchanged-if))
      (when reader-p (list :reader reader))
      (when writer-p (list :writer writer))
      (when (or accessor-p
              (not (and reader-p writer-p)))
        (list :accessor accessor))
      (when allocation-p (list :allocation allocation))
      (when documentation-p (list :documentation documentation)))))


kt

-- 
http://www.theoryyalgebra.com/

"We are what we pretend to be." -Kurt Vonnegut
From: Thomas A. Russ
Subject: Re: defmacro (or other solution) to override default slot definition in defclass...
Date: 
Message-ID: <ymitzp1uyz5.fsf@blackcat.isi.edu>
Daniel Pitts <····················@virtualinfinity.net> writes:

> I'm trying to create a macro that lets me set up some standard slots in
> a class. The goal is that all of these special slots (I call properties)
> have the specified name, and the specific initarg/reader/writer.
> This is my attempt:
> 
> (defmacro property (name &rest extra)
>          `(,name
>          :initarg ,name
>          :reader (make-symbol (concatenate 'string (symbol-name ,name)
> "-OF"))

You will be very disappointed with this.  Using MAKE-SYMBOL creates a
new, uninterned symbol.  That means that you won't be able to invoke it
by using its name.  You will need an INTERNed symbol instead.  So you
should use the function INTERN instead of MAKE-SYMBOL.

>          :writer (make-symbol (concatenate 'string "SET-" (symbol-name
> ,name)))
>          ,@extra)
> )
> (defclass thing () (
>          (property name)
>      )
> )
> 
> But it looks like defclass is getting the list (property name), instead
> of the macro expansion. Is there a way to force (property name) to be
> expanded before defclass?

See Ken Tilton's answer.

-- 
Thomas A. Russ,  USC/Information Sciences Institute