From: Coby Beck
Subject: symbol-macros and regular macros
Date: 
Message-ID: <bcm824$2plv$1@otis.netspace.net.au>
I am having trouble with something I thought would be very straight forward:

I have a macro that implements a kind of domain specific language.  It is
basically a way of condensing a whole lot of information into a compact and
more readable form that the macro code can do then work its magic on.

My goal is to be able to define reusable parts that can be stuck in
different files, write it once, use it all over.  The initial implementation
was

file1:
(defparameter *my-data* '(("stuff") :key1 (other stuff)))

and then:
file2:
(my-macro (("junk" :a 5) :key1 (info))
            #.*my-data*)))

I wanted to replace this with
file1:
(define-symbol-macro [my-data] (("stuff") :key1 (other stuff)))

and then
file2:
(my-macro (("junk" :a 5) :key1 (info))
            [my-data])))

But code inside the macro seems to be getting the [my-data] symbol.
Checking the hyper spec briefly, some simple experiments with files and top
level playing seem to confirm my [mis]understandings but both clisp and
lispworks don't like what I am trying.

Isn't the symbol replaced at read time, thus the macro should not ever see
[my-data] and is passed its expansion to use at macro-expansion time?  What
am I missing?

TIA

-- 
Coby Beck
(remove #\Space "coby 101 @ bigpond . com")

From: Thomas F. Burdick
Subject: Re: symbol-macros and regular macros
Date: 
Message-ID: <xcv65n5jmva.fsf@famine.OCF.Berkeley.EDU>
"Coby Beck" <·····@mercury.bc.ca> writes:

> I am having trouble with something I thought would be very straight forward:

 [ snip ]

> But code inside the macro seems to be getting the [my-data] symbol.
> Checking the hyper spec briefly, some simple experiments with files and top
> level playing seem to confirm my [mis]understandings but both clisp and
> lispworks don't like what I am trying.
> 
> Isn't the symbol replaced at read time, thus the macro should not ever see
> [my-data] and is passed its expansion to use at macro-expansion time?  What
> am I missing?

Nope, symbol macros are expanded at macroexpansion time.  They're just
like macros of the form (foo), but they look like variables: foo.
So:

  ;; I'm pretty sure you know what macroexpansion-time is, but
  ;; for lurkers, I'll harp on it

  * (define-symbol-macro foo (+ 1 2))
  FOO
  * foo
  3
  * 'foo ; If symbol-macro expansion happened at read-time, this would be 3
  FOO
  * (macroexpand 'foo)
  (+ 1 2)

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Kent M Pitman
Subject: Re: symbol-macros and regular macros
Date: 
Message-ID: <sfwhe6pmfil.fsf@shell01.TheWorld.com>
···@famine.OCF.Berkeley.EDU (Thomas F. Burdick) writes:

> "Coby Beck" <·····@mercury.bc.ca> writes:
> 
> > I am having trouble with something I thought would be very straight forward:
> 
>  [ snip ]
> 
> > But code inside the macro seems to be getting the [my-data] symbol.
> > Checking the hyper spec briefly, some simple experiments with files and top
> > level playing seem to confirm my [mis]understandings but both clisp and
> > lispworks don't like what I am trying.
> > 
> > Isn't the symbol replaced at read time, thus the macro should not ever see
> > [my-data] and is passed its expansion to use at macro-expansion time?  What
> > am I missing?
> 
> Nope, symbol macros are expanded at macroexpansion time.  They're just
> like macros of the form (foo), but they look like variables: foo.

Yes, exactly.  They are what in a so-called "infix language" I would 
call a "nofix operator"; that is, an operator such that you get the effect
of f() by only writing f.  In our case we get the effect of (f) by writing
only f.  ... except, of course, they are in the namespace of variables, not of
functions, which is so they can masquerade as variables.

In particular, too, they respect binding contours.  This is essential
because their primary function is to implement CLOS slots.  hence,

 (defclass foo ()
   ((a :initarg :a :accessor foo-a)))

 (defmethod frob ((foo foo))
   (with-slots (a) foo
     (let ((a            ;<-- this introduces a regular lexical variable
              (+ a 1)))  ;<-- this uses the slot
       a)))              ;<-- this is a regular lexical variable

That is, approximately, the defmethod above means:

 (defmethod frob ((foo foo))
   (symbol-macrolet ((a (slot-value foo 'a)))
     (let ((a (+ a 1)))
       a)))

or, in other words still,

 (defmethod frob ((foo foo))
   (let ((a (+ (slot-value foo 'a) 1)))
     a))

This simply would not work if done at read time.  Symbol macros must work
in lockstep with lexical environment analysis and hence have to work at
macroexpand time.

Hope that makes you feel better about what they do.

If you want a readtime expression, I recommend you define yourself a #[...].
From: Erann Gat
Subject: Re: symbol-macros and regular macros
Date: 
Message-ID: <gat-1706030942380001@192.168.1.51>
In article <···············@shell01.TheWorld.com>, Kent M Pitman
<······@world.std.com> wrote:

> In particular, too, they respect binding contours.  This is essential
> because their primary function is to implement CLOS slots.

That would be a use for lexically scoped symbol macros introduced with
symbol-macrolet, but what were global symbol macros defined with
define-symbol-macro intended to be used for?  Just wondering what the
designers had in mind.

E.
From: Kent M Pitman
Subject: Re: symbol-macros and regular macros
Date: 
Message-ID: <sfwn0ggsk2v.fsf@shell01.TheWorld.com>
···@jpl.nasa.gov (Erann Gat) writes:

> In article <···············@shell01.TheWorld.com>, Kent M Pitman
> <······@world.std.com> wrote:
> 
> > In particular, too, they respect binding contours.  This is essential
> > because their primary function is to implement CLOS slots.
> 
> That would be a use for lexically scoped symbol macros introduced with
> symbol-macrolet, but what were global symbol macros defined with
> define-symbol-macro intended to be used for?  Just wondering what the
> designers had in mind.

In CL they were added for ISLISP compatibility.

To let you define global lexicals, which again had to be shadowable
by local lexicals.

The idea had been deployed/tested out on the Lisp Machine already prior
to that.  I think it was there for general symmetry with SYMBOL-MACROLET.

Symbolics Genera 8.3 online documentation gives the example of pre-testing
the addition of a new instance variable [i.e., slot].  Remember that
Zetalisp had what I call "instant variables"; that is, they appear out
of nowhere just for having used DEFMETHOD, which is possible because
in Flavors there is only one SELF object, so there's no ambiguity
about whose instance variables to make available and there are no
clashes due to multi-methods.  Indeed, SELF is also an instant variable.
The Symbolics doc shows you doing
  (defvar x-hash-table (make-hash-table))
  (define-symbol-macro x (gethash self (make-hash-table)))
and then having you set up values of the hash table as if there were an
x allocated per-instance.  
From: Harald Hanche-Olsen
Subject: Re: symbol-macros and regular macros
Date: 
Message-ID: <pcofzm8safo.fsf@thoth.math.ntnu.no>
+ Kent M Pitman <······@world.std.com>:

| [... symbol-macros']  primary function is to implement CLOS slots.

I recently wrote the following snippet:

(defun read-unsigned-long (stream)
  (symbol-macrolet ((byte (read-byte stream)))
    (if *bigendian*
	(+ (ash byte 24) (ash byte 16) (ash byte 8) byte)
	(+ byte (ash byte 8) (ash byte 16) (ash byte 24)))))

I suppose it really is bad style to write a symbol macro with side
effects, but in such a tiny function I believe it's harmless.  And I
did think this trick was terribly clever at the time. ...

-- 
* Harald Hanche-Olsen     <URL:http://www.math.ntnu.no/~hanche/>
- Debating gives most of us much more psychological satisfaction
  than thinking does: but it deprives us of whatever chance there is
  of getting closer to the truth.  -- C.P. Snow
From: Coby Beck
Subject: Re: symbol-macros and regular macros
Date: 
Message-ID: <bcn549$7hr$1@otis.netspace.net.au>
"Kent M Pitman" <······@world.std.com> wrote in message
····················@shell01.TheWorld.com...
> ···@famine.OCF.Berkeley.EDU (Thomas F. Burdick) writes:
>
> > "Coby Beck" <·····@mercury.bc.ca> writes:
> > > Isn't the symbol replaced at read time, thus the macro should not ever
see
> > > [my-data] and is passed its expansion to use at macro-expansion time?
What
> > > am I missing?
> >
> > Nope, symbol macros are expanded at macroexpansion time.  They're just
> > like macros of the form (foo), but they look like variables: foo.
>
> Yes, exactly.  They are what in a so-called "infix language" I would
....
> This simply would not work if done at read time.  Symbol macros must work
> in lockstep with lexical environment analysis and hence have to work at
> macroexpand time.
>
> Hope that makes you feel better about what they do.

Yes, that's well and good.  I think I unitentionally internalized too far
the frequent analogy people make between them and C's #define, just a text
swap, which felt right to happen at read time.

> If you want a readtime expression, I recommend you define yourself a
#[...].

No point in that for me, #. is fine.  It is part of an ongoing effort to
provide as much convenience as possible to users of these macros and that
makes me want evaluation sometimes but not others.  I suppose could walk
through the args inside the macro and call macroexpand when I find such a
symbol or eval in similar situations, but that will require more careful
thought and design and for the moment it is very exploratory.

-- 
Coby Beck
(remove #\Space "coby 101 @ bigpond . com")