What's better about Ruby than Python?

Kenny Tilton ktilton at nyc.rr.com
Fri Aug 22 00:43:35 EDT 2003


Roy Smith wrote:
> So, is there something else that macros buy you that I'm not seeing?  
> People keep talking about how lisp macros are nothing like C/C++ macros.  
> OK, I'm willing to be educated.  How are they different?  Can somebody 
> give an example?  Keep in mind that the last time I did any serious lisp 
> was about 20 years ago.

With the C/C++ preprocessor one is limited to token replacement. I had 
great fun with that too. <g> But a Lisp macro is just another function, 
one which sees code passed it symbolically and can use all the power of 
Lisp to transmogrify it.

This macro just does token replacement:

  (defmacro cellify (class-name slot-name)
   `(defmethod ,slot-name ((self ,class-name)
			  &aux (sv (slot-value self ',slot-name)))
      (typecase sv
        (function (let ((*dependent-cell* sv))
                    (funcall sv self)))
        (otherwise sv))))

OTOH, this next macro destructures something I designed to have the same 
syntax as the Lisp DEFCLASS (for familiarity) but adds to it:

(defmacro defmodel (class superclasses (&rest slots))
   `(progn
      (defclass ,class ,superclasses
        ,slots)
      ,@(mapcar (lambda (slot)
		(destructuring-bind
		    (slotname &key initarg accessor)
		    slot
		  (declare (ignore slotname initarg))
		  `(cellify ,class ,accessor)))
	      slots)))

The mapcar keyword in Lisp iterates over the list of slots and hits each 
with the cellify macro (in turn destructuring each slot to get at the 
accessor name).

As Mr Reedy demonstrated, this much can also be achieved with 
metaclasses, and I in fact converted from macros to metaclasses in Lisp 
a few years back. I came back to macros, but only because metaclasses 
are not standard in CL and I am in the process of taking my project public.

Here's another example where substitution won't do. I am involved with 
some folks putting together Lisp teams to play RoboCup simulation 
soccer. One group is doing a straight translation of a C++ team, and 
they want to keep it literal so they do not end up rewriting the thing.

Well, the code they are copying uses enum for things like CMD_DASH, 
CMD_KICK, etc, and Lisp don't play that. Of course, Lisp handles 
symbols, but some of these enums are then used to index into arrays. So 
now Lisp need enum:

(defmacro enum (&rest names)
   (let ((prior-value -1))
     `(progn
        ,@(mapcan (lambda (name-spec)
                    (if (consp name-spec)
                        (destructuring-bind (name &optional
                                   (this-value (incf prior-value)))
                            name-spec
                          (prog1 (list
                                  `(defconstant ,name ,this-value)
                                  `(export ',name))
                            (setf prior-value this-value)))
                      (list
                       `(defconstant ,name-spec ,(incf prior-value))
                       `(export ',name-spec))))
            names))))

I need to write code to iterate over a list of names and assign them 
numbers. Notice I throw in an export the symbol from the defining 
package. Whatever it takes, I can generate that code in a macro and then 
any number of enums get ported by deleting the commas (and by changing 
midstream changes like "X=42" to (X 42).)

My favorite macro move ever was a problem of deciding how to replicate 
coded forms on a remote system by supplying just the arguments supplied 
by the author. Once the code runs all slots seem to have been created 
equal, but I simply had the DEFPANEL macro note which parameters were 
actually typed in (it gets to see the code!) and generated code to stash 
a list of the coded names in a dedicate dslot. I loved the elegance of 
identifying which arguments had been authored by noting /at compile 
time/ which arguments had been authored. :)



-- 

  kenny tilton
  clinisys, inc
  http://www.tilton-technology.com/
  ---------------------------------------------------------------
"Career highlights? I had two. I got an intentional walk from
Sandy Koufax and I got out of a rundown against the Mets."
                                                  -- Bob Uecker





More information about the Python-list mailing list