From: Pascal J. Bourguignon on
Jonathan Braud <jonathan.braud.NOSPAMTHANKYOUVERYMUCH+usenet(a)gmail.com>
writes:

> Thanks to the three of you. I guess it was high time I read a few things
> on how the reader actually reads!
>
> The solution Thomas gave appears to work.
>
> It's the way to do it that feels the most natural to me. Still, I tried
> to find one that involved read-time evaluation, and the only thing I
> could come up with was calling the macro like this:
>
> (defstruct-shadow-expand #.(progn (shadow 'lambda) 'lambda) ...)
>
> It obviously makes the macro quite inconvenient to use. So I'm wondering
> if you were thinking of something more clever. Although, unless I missed
> something again, I really don't see how a macro could have any impact on
> what happens at read time.

Actually, there is an even simplier solution:

(eval-when (:compile-toplevel :load-toplevel :execute)
(shadow 'lambda))
(defstruct-export lambda slot)


Assuming:

(eval-when (:compile-toplevel :load-toplevel :execute)
(defun sconcat (&rest args)
(intern (format nil "~{~A~}" args))))

(defmacro defstruct-export (name &rest slots)
`(PROGN
(DEFSTRUCT ,name ,slots)
,@(mapcar (lambda (sym) `(EXPORT ',sym))
(cons (sconcat 'make- name)
(mapcar (lambda (slot)
(sconcat name '- slot))
slots)))))


(macroexpand '(defstruct-export lambda slot))
--> (PROGN (DEFSTRUCT LAMBDA (SLOT))
(EXPORT 'MAKE-LAMBDA)
(EXPORT 'LAMBDA-SLOT))


The point is to realize that both the REPL, LOAD, and COMPILE-FILE
interspece reading with (evaluating and printing) or compiling
(at least compile-time side-effects evaluation).

When you give to the REPL, or when you compile a file containing:

(eval-when (:compile-toplevel :load-toplevel :execute)
(shadow 'lambda))
(defstruct-export lambda slot)

1. (eval-when (:compile-toplevel :load-toplevel :execute)
(shadow 'lambda))
is read. the symbol in the quote form is CL:LAMBDA, with the right
assumptions.

2. (eval-when (:compile-toplevel :load-toplevel :execute)
(shadow 'lambda))
is evaluated. CL:LAMBDA is no more accessible from *PACKAGE*.

3. (defstruct-export lambda slot) is read. The second symbol is a new
symbol named "LAMBDA" interned in *PACKAGE*.

4. (defstruct-export lambda slot) is macroexpanded (in the REPL or LOAD)
or mininal-compiled (in COMPILE-FILE).

5. (PROGN (DEFSTRUCT LAMBDA (SLOT))
(EXPORT 'MAKE-LAMBDA)
(EXPORT 'LAMBDA-SLOT))
is executed (in the REPL or LOAD) or compiled (in COMPPILE-FILE).
Since LAMBDA is not CL:LAMBDA, everything goes well.



There's even a simplier way, which is to put "LAMBDA" in the :shadow
list of the defpackage form for the package where this lambda structure
is defined:

(defpackage "EXAMPLE"
(:use "CL")
(:shadow "LAMBDA"))

(in-package "EXAMPLE")

(defstruct-export lambda slot)


;; Do not fight the CL way!
--
__Pascal Bourguignon__
From: Jonathan Braud on
In article <878w7yq1fx.fsf(a)galatea.lan.informatimago.com>,
pjb(a)informatimago.com (Pascal J. Bourguignon) wrote:

> Actually, there is an even simplier solution:
>
> (eval-when (:compile-toplevel :load-toplevel :execute)
> (shadow 'lambda))
> (defstruct-export lambda slot)
>

But this works only because (eval-when ... (shadow 'lambda)) is
evaluated before (defstruct-export lambda slot) is even read, right?
If I tried to put it in a macro, I would get the same problem I had in
the first post.

> There's even a simplier way, which is to put "LAMBDA" in the :shadow
> list of the defpackage form for the package where this lambda structure
> is defined:
>
> (defpackage "EXAMPLE"
> (:use "CL")
> (:shadow "LAMBDA"))
>
> (in-package "EXAMPLE")
>
> (defstruct-export lambda slot)
>

Yes, except the original purpose was to let a macro take care of all
that. Using the shadow list is just cheating :-).
From: Thomas A. Russ on
Jonathan Braud <jonathan.braud.NOSPAMTHANKYOUVERYMUCH+usenet(a)gmail.com> writes:

> In article <878w7yq1fx.fsf(a)galatea.lan.informatimago.com>,
> pjb(a)informatimago.com (Pascal J. Bourguignon) wrote:
>
> > Actually, there is an even simplier solution:
> >
> > (eval-when (:compile-toplevel :load-toplevel :execute)
> > (shadow 'lambda))
> > (defstruct-export lambda slot)
> >
>
> But this works only because (eval-when ... (shadow 'lambda)) is
> evaluated before (defstruct-export lambda slot) is even read, right?
> If I tried to put it in a macro, I would get the same problem I had in
> the first post.

Correct.

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
















From: Pascal J. Bourguignon on
Jonathan Braud <jonathan.braud.NOSPAMTHANKYOUVERYMUCH+usenet(a)gmail.com>
writes:

> In article <878w7yq1fx.fsf(a)galatea.lan.informatimago.com>,
> pjb(a)informatimago.com (Pascal J. Bourguignon) wrote:
>
>> Actually, there is an even simplier solution:
>>
>> (eval-when (:compile-toplevel :load-toplevel :execute)
>> (shadow 'lambda))
>> (defstruct-export lambda slot)
>>
>
> But this works only because (eval-when ... (shadow 'lambda)) is
> evaluated before (defstruct-export lambda slot) is even read, right?
> If I tried to put it in a macro, I would get the same problem I had in
> the first post.
>
>> There's even a simplier way, which is to put "LAMBDA" in the :shadow
>> list of the defpackage form for the package where this lambda structure
>> is defined:
>>
>> (defpackage "EXAMPLE"
>> (:use "CL")
>> (:shadow "LAMBDA"))
>>
>> (in-package "EXAMPLE")
>>
>> (defstruct-export lambda slot)
>>
>
> Yes, except the original purpose was to let a macro take care of all
> that. Using the shadow list is just cheating :-).

Well, since you insist to get the rope, here it is.

You can do it at run-time. (You could do it at macroexpansion time but
it would be meaningless, since you don't control when this occurs).


(eval-when (:compile-toplevel :load-toplevel :execute)
(defun strcat (&rest args) (format nil "~{~A~}" args)))

(defmacro defstruct-export (name &rest slots)
`(PROGN
(shadow ',name)
(eval `(DEFSTRUCT ,(intern ,(string name)) ,',@slots))
(export (mapcar (function intern)
',(cons (strcat 'make- name)
(mapcar (lambda (slot) (strcat name '- slot))
slots))))
(values))) ; it would be quite purposeless to return ',name like other def* macros.

(macroexpand-1 '(defstruct-export lambda slot-1 slot-2))
--> (PROGN (SHADOW 'LAMBDA)
(EVAL (CONS 'DEFSTRUCT (CONS (INTERN "LAMBDA") '(SLOT-1 SLOT-2))))
(EXPORT (MAPCAR #'INTERN '("MAKE-LAMBDA" "LAMBDA-SLOT-1" "LAMBDA-SLOT-2")))
(VALUES)) ;
T

The problem of this, is that the shadowing is done at run-time,
therefore the code that is read after a call to defstruct-export will
still intern the old symbol, which will be shadowed. Now, you would
have to load the source in two step: one little part containing the
defstruct-export form, which can be loaded and compiled at compilation
time, and another with the rest of the code, which must be loaded (and
possibly compiled) at run-time.


And if you try to do it at macro expansion time, then you will just lost
control over when the shadowing occurs so you won't be in a better
situation.


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