From: sycoogtit
Subject: Macro to create a class
Date: 
Message-ID: <86777674-0993-4a6b-af14-e94aa7a96c00@r15g2000prd.googlegroups.com>
I have a really simple class that is repetitive:

(defpclass book ()
  ((title :accessor title :initarg "" :index t)
    (author :accessor author :initarg "" :index t)
    ...))

I've created a macro so I don't have to do that, and so it's easier to
add fields later:

(defmacro book-macro (fields)
  `(defpclass book ()
    ,(let ((params ()))
      (dolist (field fields)
        (push `(,field :accessor ,field :initarg "" :index t) params))
      params)))

When I expand the macro, it works how I would like: (macroexpand-1
'(book-macro (title author isbn)))

(DEFPCLASS BOOK NIL
            (ISBN :ACCESSOR ISBN :INITARG "" :INDEX T)
            (AUTHOR :ACCESSOR AUTHOR :INITARG "" :INDEX T)
            (TITLE :ACCESSOR TITLE :INITARG "" :INDEX T)))

So the problem is, when I load the file that contains this class, I
can't get it to define this class so I can make an instance of a
book.  Any ideas?  I'm a total Lisp newbie, so forgive me if this is a
stupid question.

Thanks
Scott

From: Thomas A. Russ
Subject: Re: Macro to create a class
Date: 
Message-ID: <ymiskt9dbj0.fsf@blackcat.isi.edu>
sycoogtit <·········@gmail.com> writes:

> I have a really simple class that is repetitive:
> 
> (defpclass book ()
>   ((title :accessor title :initarg "" :index t)
>     (author :accessor author :initarg "" :index t)
>     ...))

Um, I don't recognize "defPclass", so I'm not quite sure what sort of
syntax you need to come up with.

> I've created a macro so I don't have to do that, and so it's easier to
> add fields later:
> 
> (defmacro book-macro (fields)
>   `(defpclass book ()
>     ,(let ((params ()))
>       (dolist (field fields)
>         (push `(,field :accessor ,field :initarg "" :index t) params))
>       params)))

Personal style note:  I would tend to put the LET binding of params and
the DOLIST outside of the expansion and just include the expansion
itself inside the backquote.  But that's clearly just a style issue.

Another style note:  This would probably be a good macro to call DEFBOOK
or DEF-BOOK, since it creates definitions.

You might also want to make this macro a LOT more general by taking a
NAME parameter as well, to use as the name of the class.  That way you
won't need a separate macro for magazines, etc.  Not sure if you want to
have an option for including the superclasses as well.  Perhaps
something like:

(defmacro def-myclass (name supers fields)
   (let ((slots ()))
      (dolist (field fields)
         (push `(,field :accessor ,field :initarg "" :index t)
               slots))
     `(defpclass ,name ,supers
            ,slots)))

> 
> When I expand the macro, it works how I would like: (macroexpand-1
> '(book-macro (title author isbn)))
> 
> (DEFPCLASS BOOK NIL
>             (ISBN :ACCESSOR ISBN :INITARG "" :INDEX T)
>             (AUTHOR :ACCESSOR AUTHOR :INITARG "" :INDEX T)
>             (TITLE :ACCESSOR TITLE :INITARG "" :INDEX T)))

Um, something's wrong here.  It seems that a parenthesis is missing at
the start of your slots.  I'm assuming it went missing during the
cut-and-paste.

> So the problem is, when I load the file that contains this class, I
> can't get it to define this class so I can make an instance of a
> book.  Any ideas?  I'm a total Lisp newbie, so forgive me if this is a
> stupid question.

Hmmm.  A couple more questions, then:

1.  Do you get any error messages while loading the file?
2.  Is BOOK-MACRO defined before it is used?
3.  What about DEFPCLASS?
4.  I presume that (find-class 'book) returns NIL?
5.  What happens when you try to create an instance?

-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Kenny
Subject: Re: Macro to create a class
Date: 
Message-ID: <48a224f0$0$29511$607ed4bc@cv.net>
sycoogtit wrote:
> I have a really simple class that is repetitive:
> 
> (defpclass book ()
>   ((title :accessor title :initarg "" :index t)
>     (author :accessor author :initarg "" :index t)
>     ...))
> 
> I've created a macro so I don't have to do that, and so it's easier to
> add fields later:
> 
> (defmacro book-macro (fields)
>   `(defpclass book ()
>     ,(let ((params ()))
>       (dolist (field fields)
>         (push `(,field :accessor ,field :initarg "" :index t) params))
>       params)))
> 
> When I expand the macro, it works how I would like: (macroexpand-1
> '(book-macro (title author isbn)))
> 
> (DEFPCLASS BOOK NIL
>             (ISBN :ACCESSOR ISBN :INITARG "" :INDEX T)
>             (AUTHOR :ACCESSOR AUTHOR :INITARG "" :INDEX T)
>             (TITLE :ACCESSOR TITLE :INITARG "" :INDEX T)))
> 
> So the problem is, when I load the file that contains this class, I
> can't get it to define this class so I can make an instance of a
> book.  Any ideas?  I'm a total Lisp newbie, so forgive me if this is a
> stupid question.

Well, your big mistake is a crappy problem description. :)

What the hell is defpclass?

What error do you get?

Are you sure the list of slots should not be in its own list (ie, I 
would expect defpclass to ape the syntax of defclass and want:

   (defpclass book nil
     ( ; start slot list
       (isbn ..etc)
       (title ....)
     ) ; end slot list
   ) ; end defpclass

Not that we use that C-style for handling {}s, just so you see what I am 
  suggesting.

kt

-- 

$$$$$: http://www.theoryyalgebra.com/
Cells: http://common-lisp.net/project/cells/
BSlog: http://smuglispweeny.blogspot.com/
From: Pascal J. Bourguignon
Subject: Re: Macro to create a class
Date: 
Message-ID: <87wsilemqq.fsf@hubble.informatimago.com>
sycoogtit <·········@gmail.com> writes:

> I have a really simple class that is repetitive:
>
> (defpclass book ()
>   ((title :accessor title :initarg "" :index t)
>     (author :accessor author :initarg "" :index t)
>     ...))
>
> I've created a macro so I don't have to do that, and so it's easier to
> add fields later:
>
> (defmacro book-macro (fields)
>   `(defpclass book ()
>     ,(let ((params ()))
>       (dolist (field fields)
>         (push `(,field :accessor ,field :initarg "" :index t) params))
>       params)))
>
> When I expand the macro, it works how I would like: (macroexpand-1
> '(book-macro (title author isbn)))
>
> (DEFPCLASS BOOK NIL
>             (ISBN :ACCESSOR ISBN :INITARG "" :INDEX T)
>             (AUTHOR :ACCESSOR AUTHOR :INITARG "" :INDEX T)
>             (TITLE :ACCESSOR TITLE :INITARG "" :INDEX T)))
>
> So the problem is, when I load the file that contains this class, I
> can't get it to define this class so I can make an instance of a
> book.  Any ideas?  I'm a total Lisp newbie, so forgive me if this is a
> stupid question.

Usually, :initarg is given a keyword that is used to specify the
initial argument for the slot. Perhaps defpclass doesn't accept a
string here?

Otherwise, given that defpclass is not defined in COMMON-LISP, you
must of course ensure that it is defined before you used it from your
book macro.

You should try to generalize it.  A book macro is totally useless (but
perhaps to define a book class, but a book in the universe is
insignificant).  So, let's do rather a DEFINE-QUICK-CLASS macro:


C/USER[8]> (defmacro define-quick-class (classname fields)
             `(defclass ,classname ()
                ,(let ((params ()))
                      (dolist (field fields params)
                        (push `(,field :accessor ,field :initarg ,(intern (string field) #.(find-package "KEYWORD")))
                              params)))))
DEFINE-QUICK-CLASS
C/USER[9]> (macroexpand-1 '(define-quick-class book (title author isbn)))
(DEFCLASS BOOK NIL ((ISBN :ACCESSOR ISBN :INITARG :ISBN) (AUTHOR :ACCESSOR AUTHOR :INITARG :AUTHOR) (TITLE :ACCESSOR TITLE :INITARG :TITLE))) ;
T
C/USER[10]> (define-quick-class book (title author isbn))
#1=#<STANDARD-CLASS BOOK>
C/USER[11]> (inspect (make-instance 'book :title "Practical Common Lisp" :author "Peter Seibel" :isbn "1590592395"))
#<COMMON-LISP-USER::BOOK #x207C0816>:  standard object
 type: COMMON-LISP-USER::BOOK
0 [ISBN]:  "1590592395"
1 [AUTHOR]:  "Peter Seibel"
2 [TITLE]:  "Practical Common Lisp"
INSPECT-- type :h for help; :q to return to the REPL ---> :q

C/USER[12]> 


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

"Our users will know fear and cower before our software! Ship it!
Ship it and let them flee like the dogs they are!"
From: sycoogtit
Subject: Re: Macro to create a class
Date: 
Message-ID: <74d783e7-2c81-4ddb-b8d1-f54b270ad677@a3g2000prm.googlegroups.com>
Wow, there are a bunch of great replies here.  I really appreciate so
much help in so little time!  I'll answer each reply.

On Aug 12, 6:03 pm, Kenny <·········@gmail.com> wrote:
>
> What the hell is defpclass?

Sorry, I should have been more informative about that.  defpclass is
from the Elephant (http://common-lisp.net/project/elephant/)
Database... library?  It takes the same (I think) parameters as
depclass.

>
> What error do you get?

There is no class named BOOK.

>
> Are you sure the list of slots should not be in its own list (ie, I
> would expect defpclass to ape the syntax of defclass and want:
>
>    (defpclass book nil
>      ( ; start slot list
>        (isbn ..etc)
>        (title ....)
>      ) ; end slot list
>    ) ; end defpclass
>

I actually lost a parenthesis in my copy-paste, so it does get
expanded into what you've suggested.


On Aug 12, 6:05 pm, ····@sevak.isi.edu (Thomas A. Russ) wrote:
>
> Personal style note:  I would tend to put the LET binding of params and
> the DOLIST outside of the expansion and just include the expansion
> itself inside the backquote.  But that's clearly just a style issue.
>
> Another style note:  This would probably be a good macro to call DEFBOOK
> or DEF-BOOK, since it creates definitions.
>
> You might also want to make this macro a LOT more general by taking a
> NAME parameter as well, to use as the name of the class.  That way you
> won't need a separate macro for magazines, etc.  Not sure if you want to
> have an option for including the superclasses as well.  Perhaps
> something like:
>
> (defmacro def-myclass (name supers fields)
>    (let ((slots ()))
>       (dolist (field fields)
>          (push `(,field :accessor ,field :initarg "" :index t)
>                slots))
>      `(defpclass ,name ,supers
>             ,slots)))
>
>

That is much better.  Thanks for the style tips!  I clearly need them!

> > (DEFPCLASS BOOK NIL
> >             (ISBN :ACCESSOR ISBN :INITARG "" :INDEX T)
> >             (AUTHOR :ACCESSOR AUTHOR :INITARG "" :INDEX T)
> >             (TITLE :ACCESSOR TITLE :INITARG "" :INDEX T)))
>
> Um, something's wrong here.  It seems that a parenthesis is missing at
> the start of your slots.  I'm assuming it went missing during the
> cut-and-paste.

Yes, you're right.  There's another parenthesis before ISBN.

>
> Hmmm.  A couple more questions, then:
>
> 1.  Do you get any error messages while loading the file?

No errors or warnings.

> 2.  Is BOOK-MACRO defined before it is used?
> 3.  What about DEFPCLASS?

Well, I'm not sure I'm "using" it correctly.  I do:
(defpclass book-macro ...)
(macroexpand-1 '(book-macro ...))

I was hoping that the expansion would magically include that
definition, but I guess it isn't.

> 4.  I presume that (find-class 'book) returns NIL?

Hm.  (find-class 'book) returns an error:
There is no class named BOOK.

> 5.  What happens when you try to create an instance?

Same as above.


On Aug 12, 7:18 pm, ····@informatimago.com (Pascal J. Bourguignon)
wrote:

> Usually, :initarg is given a keyword that is used to specify the
> initial argument for the slot. Perhaps defpclass doesn't accept a
> string here?
>
> Otherwise, given that defpclass is not defined in COMMON-LISP, you
> must of course ensure that it is defined before you used it from your
> book macro.

Ah-hah.  Indeed, :initarg does not accept a string.  I just removed
that part from the macro, but it still doesn't magically load.
However, I can copy-paste the expansion into REPL and the class is
then defined.

>
> You should try to generalize it.  A book macro is totally useless (but
> perhaps to define a book class, but a book in the universe is
> insignificant).  So, let's do rather a DEFINE-QUICK-CLASS macro:
>
> C/USER[8]> (defmacro define-quick-class (classname fields)
>              `(defclass ,classname ()
>                 ,(let ((params ()))
>                       (dolist (field fields params)
>                         (push `(,field :accessor ,field :initarg ,(intern (string field) #.(find-package "KEYWORD")))
>                               params)))))
> DEFINE-QUICK-CLASS
> C/USER[9]> (macroexpand-1 '(define-quick-class book (title author isbn)))
> (DEFCLASS BOOK NIL ((ISBN :ACCESSOR ISBN :INITARG :ISBN) (AUTHOR :ACCESSOR AUTHOR :INITARG :AUTHOR) (TITLE :ACCESSOR TITLE :INITARG :TITLE))) ;
> T
> C/USER[10]> (define-quick-class book (title author isbn))
> #1=#<STANDARD-CLASS BOOK>
> C/USER[11]> (inspect (make-instance 'book :title "Practical Common Lisp" :author "Peter Seibel" :isbn "1590592395"))

Ah-hah!  That's it!  I expanded the macro and then thought I could
just make an instance.  Once I added (book-macro (title author isbn)),
it all worked!

Thanks again everyone for all your help!
Scott
From: Kenny
Subject: Re: Macro to create a class
Date: 
Message-ID: <48a269d1$0$20926$607ed4bc@cv.net>
sycoogtit wrote:
> Wow, there are a bunch of great replies here.  I really appreciate so
> much help in so little time!  I'll answer each reply.
> 
> On Aug 12, 6:03 pm, Kenny <·········@gmail.com> wrote:
>> What the hell is defpclass?
> 
> Sorry, I should have been more informative about that.  defpclass is
> from the Elephant (http://common-lisp.net/project/elephant/)
> Database... library?  It takes the same (I think) parameters as
> depclass.
> 
>> What error do you get?
> 
> There is no class named BOOK.
> 
>> Are you sure the list of slots should not be in its own list (ie, I
>> would expect defpclass to ape the syntax of defclass and want:
>>
>>    (defpclass book nil
>>      ( ; start slot list
>>        (isbn ..etc)
>>        (title ....)
>>      ) ; end slot list
>>    ) ; end defpclass
>>
> 
> I actually lost a parenthesis in my copy-paste, so it does get
> expanded into what you've suggested.
> 
> 
> On Aug 12, 6:05 pm, ····@sevak.isi.edu (Thomas A. Russ) wrote:
>> Personal style note:  I would tend to put the LET binding of params and
>> the DOLIST outside of the expansion and just include the expansion
>> itself inside the backquote.  But that's clearly just a style issue.
>>
>> Another style note:  This would probably be a good macro to call DEFBOOK
>> or DEF-BOOK, since it creates definitions.
>>
>> You might also want to make this macro a LOT more general by taking a
>> NAME parameter as well, to use as the name of the class.  That way you
>> won't need a separate macro for magazines, etc.  Not sure if you want to
>> have an option for including the superclasses as well.  Perhaps
>> something like:
>>
>> (defmacro def-myclass (name supers fields)
>>    (let ((slots ()))
>>       (dolist (field fields)
>>          (push `(,field :accessor ,field :initarg "" :index t)
>>                slots))
>>      `(defpclass ,name ,supers
>>             ,slots)))
>>
>>
> 
> That is much better.  Thanks for the style tips!  I clearly need them!
> 
>>> (DEFPCLASS BOOK NIL
>>>             (ISBN :ACCESSOR ISBN :INITARG "" :INDEX T)
>>>             (AUTHOR :ACCESSOR AUTHOR :INITARG "" :INDEX T)
>>>             (TITLE :ACCESSOR TITLE :INITARG "" :INDEX T)))
>> Um, something's wrong here.  It seems that a parenthesis is missing at
>> the start of your slots.  I'm assuming it went missing during the
>> cut-and-paste.
> 
> Yes, you're right.  There's another parenthesis before ISBN.
> 
>> Hmmm.  A couple more questions, then:
>>
>> 1.  Do you get any error messages while loading the file?
> 
> No errors or warnings.
> 
>> 2.  Is BOOK-MACRO defined before it is used?
>> 3.  What about DEFPCLASS?
> 
> Well, I'm not sure I'm "using" it correctly.  I do:
> (defpclass book-macro ...)
> (macroexpand-1 '(book-macro ...))
> 
> I was hoping that the expansion would magically include that
> definition, but I guess it isn't.
> 
>> 4.  I presume that (find-class 'book) returns NIL?
> 
> Hm.  (find-class 'book) returns an error:
> There is no class named BOOK.

Find-class, btw, also takes a (first) optional argument, errorp.

> 
>> 5.  What happens when you try to create an instance?
> 
> Same as above.
> 
> 
> On Aug 12, 7:18 pm, ····@informatimago.com (Pascal J. Bourguignon)
> wrote:
> 
>> Usually, :initarg is given a keyword that is used to specify the
>> initial argument for the slot. Perhaps defpclass doesn't accept a
>> string here?
>>
>> Otherwise, given that defpclass is not defined in COMMON-LISP, you
>> must of course ensure that it is defined before you used it from your
>> book macro.
> 
> Ah-hah.  Indeed, :initarg does not accept a string.  I just removed
> that part from the macro, but it still doesn't magically load.
> However, I can copy-paste the expansion into REPL and the class is
> then defined.
> 
>> You should try to generalize it.  A book macro is totally useless (but
>> perhaps to define a book class, but a book in the universe is
>> insignificant).  So, let's do rather a DEFINE-QUICK-CLASS macro:
>>
>> C/USER[8]> (defmacro define-quick-class (classname fields)
>>              `(defclass ,classname ()
>>                 ,(let ((params ()))
>>                       (dolist (field fields params)
>>                         (push `(,field :accessor ,field :initarg ,(intern (string field) #.(find-package "KEYWORD")))
>>                               params)))))
>> DEFINE-QUICK-CLASS
>> C/USER[9]> (macroexpand-1 '(define-quick-class book (title author isbn)))
>> (DEFCLASS BOOK NIL ((ISBN :ACCESSOR ISBN :INITARG :ISBN) (AUTHOR :ACCESSOR AUTHOR :INITARG :AUTHOR) (TITLE :ACCESSOR TITLE :INITARG :TITLE))) ;
>> T
>> C/USER[10]> (define-quick-class book (title author isbn))
>> #1=#<STANDARD-CLASS BOOK>
>> C/USER[11]> (inspect (make-instance 'book :title "Practical Common Lisp" :author "Peter Seibel" :isbn "1590592395"))
> 
> Ah-hah!  That's it!  I expanded the macro and then thought I could
> just make an instance.  Once I added (book-macro (title author isbn)),
> it all worked!
> 
> Thanks again everyone for all your help!
> Scott

We are soooo slipping. There was a day when the OP would at this point 
be no more than a bloody carcass left for the jackals and vultures. Not 
sure the CLHS specifies in which order.

<sigh>

kenny

-- 

$$$$$: http://www.theoryyalgebra.com/
Cells: http://common-lisp.net/project/cells/
BSlog: http://smuglispweeny.blogspot.com/
From: D Herring
Subject: Re: Macro to create a class
Date: 
Message-ID: <RYidnQYgNoSy7z_VnZ2dnUVZ_orinZ2d@comcast.com>
Kenny wrote:

> We are soooo slipping. There was a day when the OP would at this point 
> be no more than a bloody carcass left for the jackals and vultures. Not 
> sure the CLHS specifies in which order.
> 
> <sigh>

Chalk it up to the end of summer.  I'm sure you'll return to form soon 
enough.

- Daniel