From: Andras Simon
Subject: delaying macroexpansion
Date: 
Message-ID: <vcd7jrgbgqc.fsf@csusza.math.bme.hu>
I'm trying to write a macro NEW-CLASS for abcl that creates a Java
class (at load time), and defines a lispy interface to it using jfli's
DEF-JAVA-CLASS macro. The problem is that DEF-JAVA-CLASS's expansion
depends on the class it is called for, which is not available at
compile-time. At present I delay the expansion like this

(defmacro new-class (...)
...
  `(progn 
    ;;JRC is the function that creates/loads the Java class
    (jrc ,class-name ,super-name ,interfaces ...)
    (funcall #'(lambda () (def-java-class ,class-name))))))))

and it works, but I'm almost sure that that is accidental. 

What are my options, given that I'd like to treat DEF-JAVA-CLASS as
given, if possible?

Andras

From: Peter Seibel
Subject: Re: delaying macroexpansion
Date: 
Message-ID: <m3hdqkct2h.fsf@javamonkey.com>
Andras Simon <······@math.bme.hu> writes:

> I'm trying to write a macro NEW-CLASS for abcl that creates a Java
> class (at load time), and defines a lispy interface to it using jfli's
> DEF-JAVA-CLASS macro. The problem is that DEF-JAVA-CLASS's expansion
> depends on the class it is called for, which is not available at
> compile-time. At present I delay the expansion like this

Sounds like you need to use EVAL-WHEN to ensure that something--not
clear to me what exactly from your description--happens at compile
time as well as, or instead of, load time.

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Andras Simon
Subject: Re: delaying macroexpansion
Date: 
Message-ID: <vcd3c24bcre.fsf@csusza.math.bme.hu>
Peter Seibel <·····@javamonkey.com> writes:

> Andras Simon <······@math.bme.hu> writes:
> 
> > I'm trying to write a macro NEW-CLASS for abcl that creates a Java
> > class (at load time), and defines a lispy interface to it using jfli's
> > DEF-JAVA-CLASS macro. The problem is that DEF-JAVA-CLASS's expansion
> > depends on the class it is called for, which is not available at
> > compile-time. At present I delay the expansion like this
> 
> Sounds like you need to use EVAL-WHEN to ensure that something--not
> clear to me what exactly from your description--happens at compile
> time as well as, or instead of, load time.

Actually, it's the other way round. I'd like macroexpansion _not_ to
happen at compile time. And I don't think that wrapping the call to
DEF-JAVA-CLASS (in the expansion of NEW-CLASS) in an
(eval-when (:load-toplevel :execute) ..) will stop D-J-C from expanding
when NEW-CLASS is compiled.

Andras
From: Coby Beck
Subject: Re: delaying macroexpansion
Date: 
Message-ID: <loMYc.76714$X12.14095@edtnps84>
"Andras Simon" <······@math.bme.hu> wrote in message
····················@csusza.math.bme.hu...
>
> Actually, it's the other way round. I'd like macroexpansion _not_ to
> happen at compile time. And I don't think that wrapping the call to
> DEF-JAVA-CLASS (in the expansion of NEW-CLASS) in an
> (eval-when (:load-toplevel :execute) ..) will stop D-J-C from expanding
> when NEW-CLASS is compiled.

It sounds like you really want to write a function that is called when you
load a file.  Indeed you could perhaps write a macro that expands into:
(funcall (lamdbda (...)...)...)

I think not wanting a macro to expand at macro-expansion time is a strong
hint that it is a function.

-- 
Coby Beck
(remove #\Space "coby 101 @ big pond . com")
From: Andras Simon
Subject: Re: delaying macroexpansion
Date: 
Message-ID: <vcdk6veajgt.fsf@csusza.math.bme.hu>
"Coby Beck" <·····@mercury.bc.ca> writes:

> "Andras Simon" <······@math.bme.hu> wrote in message
> ····················@csusza.math.bme.hu...
> >
> > Actually, it's the other way round. I'd like macroexpansion _not_ to
> > happen at compile time. And I don't think that wrapping the call to
> > DEF-JAVA-CLASS (in the expansion of NEW-CLASS) in an
> > (eval-when (:load-toplevel :execute) ..) will stop D-J-C from expanding
> > when NEW-CLASS is compiled.
> 
> It sounds like you really want to write a function that is called when you
> load a file.  Indeed you could perhaps write a macro that expands into:
> (funcall (lamdbda (...)...)...)
> 
> I think not wanting a macro to expand at macro-expansion time is a strong
> hint that it is a function.

Indeed, it'd be nice if there was a functional interface to what
def-java-class does. (But then the same holds for other defining
macros like defun and defclass, doesn't it?)

Andras
From: Coby Beck
Subject: Re: delaying macroexpansion
Date: 
Message-ID: <O3aZc.83311$X12.12192@edtnps84>
"Andras Simon" <······@math.bme.hu> wrote in message
····················@csusza.math.bme.hu...
> "Coby Beck" <·····@mercury.bc.ca> writes:
>
> > I think not wanting a macro to expand at macro-expansion time is a
strong
> > hint that it is a function.
>
> Indeed, it'd be nice if there was a functional interface to what
> def-java-class does. (But then the same holds for other defining
> macros like defun and defclass, doesn't it?)

I've only glanced through the other discussion in the thread so ignore and
forgive me if there is a subtlety I'm missing...but

It still sounds like you might be able to just run a function at load time.
You can have functions do what defun does too.

I once wrote code that at run time would read a data specification file and
then write and compile parsing functions that were then used over and over.
They were lambdas kept as slots on an special object but if it warrants it
you can setf (symbol-function 'foo).

Unless def-java-class contains alot of structured arguments it may be better
as a function.  If it does take a lot of structured arguments, say like
defclass, it could still expand into something that is full of function
calls that do the naughty-bits with all the info now available at load time.

-- 
Coby Beck
(remove #\Space "coby 101 @ big pond . com")
From: Wade Humeniuk
Subject: Re: delaying macroexpansion
Date: 
Message-ID: <WLTYc.77897$X12.64062@edtnps84>
Andras Simon wrote:
> I'm trying to write a macro NEW-CLASS for abcl that creates a Java
> class (at load time), and defines a lispy interface to it using jfli's
> DEF-JAVA-CLASS macro. The problem is that DEF-JAVA-CLASS's expansion
> depends on the class it is called for, which is not available at
> compile-time. At present I delay the expansion like this
> 
> (defmacro new-class (...)
> ...
>   `(progn 
>     ;;JRC is the function that creates/loads the Java class
>     (jrc ,class-name ,super-name ,interfaces ...)
>     (funcall #'(lambda () (def-java-class ,class-name))))))))
> 
> and it works, but I'm almost sure that that is accidental. 
> 

I am not exactly sure what the problem is, but I think its that
until jrc is actually called def-java-class cannot be expanded
because some configuration info is needed to build the java-class.
Or is more done? (Like interfacing to java and exchanging some
configuration info?)

One way might be:

(defmacro new-class (class-name super-name interfaces)
   `(progn
      (jrc ,class-name ,super-name ,interfaces)
      (eval '(def-java-class ,class-name))))

But I pretty sure that

(defmacro new-class (class-name super-name interfaces)
   `(eval-when (:compile-toplevel :load-toplevel :execute)
      (jrc ,class-name ,super-name ,interfaces)
      (def-java-class ,class-name)))

will do what you want.  The compiler should compile and evaluate
the call to jrc before the compilation of the call to def-java-class
(or does the expansion of def-java-class change for each instantiation
of the Lisp system?).

Wade
From: Andras Simon
Subject: Re: delaying macroexpansion
Date: 
Message-ID: <vcdy8jva1zt.fsf@csusza.math.bme.hu>
Wade Humeniuk <····································@telus.net> writes:

> Andras Simon wrote:
> > I'm trying to write a macro NEW-CLASS for abcl that creates a Java
> > class (at load time), and defines a lispy interface to it using jfli's
> > DEF-JAVA-CLASS macro. The problem is that DEF-JAVA-CLASS's expansion
> > depends on the class it is called for, which is not available at
> > compile-time. At present I delay the expansion like this
> > (defmacro new-class (...)
> > ...
> >   `(progn     ;;JRC is the function that creates/loads the Java class
> >     (jrc ,class-name ,super-name ,interfaces ...)
> >     (funcall #'(lambda () (def-java-class ,class-name))))))))
> > and it works, but I'm almost sure that that is accidental.
> 
> I am not exactly sure what the problem is, but I think its that
> until jrc is actually called def-java-class cannot be expanded

That's right.

> because some configuration info is needed to build the java-class.

Not quite: it's jrc that builds/loads the Java class, and
def-java-class expands into code that defines the Lisp functions that
interace to it. The expansion (the process, not the result) uses Java
reflection to decide what to define, so the Java class must be
loaded before def-java-class can expand. 

> Or is more done? (Like interfacing to java and exchanging some
> configuration info?)
> 
> One way might be:
> 
> (defmacro new-class (class-name super-name interfaces)
>    `(progn
>       (jrc ,class-name ,super-name ,interfaces)
>       (eval '(def-java-class ,class-name))))

This works and is better than my original proposal (funcall (lambda ()
(def-java-class ,classname))) because this will definitely not expand
def-java-class, at least AFAICS. Thanks for the tip!

> 
> But I pretty sure that
> 
> (defmacro new-class (class-name super-name interfaces)
>    `(eval-when (:compile-toplevel :load-toplevel :execute)
>       (jrc ,class-name ,super-name ,interfaces)
>       (def-java-class ,class-name)))
> 
> will do what you want.  The compiler should compile and evaluate
> the call to jrc before the compilation of the call to def-java-class
> (or does the expansion of def-java-class change for each instantiation
> of the Lisp system?).

The expansion of def-java-class is dependent on the Java environment
(the superclass of the class NEW-CLASS is defining may have more or
less methods, and that affects what def-java-class expands into). But
that doesn't seem like a big problem. What does is that it's not clear
to me how eval-when controls macro-expansion in this case. E.g., given

(defmacro def-java-class () 
  (print "expanding def-java-class") 
  '(print "executing def-java-class"))

(defmacro new-class ()
  '(eval-when (:compile-toplevel :load-toplevel :execute)
    (print "loading java class")
    (def-java-class)))

compiling a file that has (new-class) in it gives

"loading java class" 
"expanding def-java-class" 
"executing def-java-class" 

and loading the compiled file gives

"loading java class" 
"executing def-java-class" 

in both SBCL and ABCL, which is good, but is this order guaranteed? 
But if I evaluate (new-class) in the REPL, I get

CL-USER> (new-class)

"expanding def-java-class" 
"loading java class" 
"executing def-java-class" 

in ABCL, and that's the problem. If this is an ABCL bug, I'd be happy
to pass on the relevant chapter and verse from CLHS to Peter Graves,
but I'd be surprised. 

Andras
From: Wade Humeniuk
Subject: Re: delaying macroexpansion
Date: 
Message-ID: <f1%Yc.56135$S55.52847@clgrps12>
Andras Simon wrote:

> The expansion of def-java-class is dependent on the Java environment
> (the superclass of the class NEW-CLASS is defining may have more or
> less methods, and that affects what def-java-class expands into). But
> that doesn't seem like a big problem. What does is that it's not clear
> to me how eval-when controls macro-expansion in this case. E.g., given
> 
> (defmacro def-java-class () 
>   (print "expanding def-java-class") 
>   '(print "executing def-java-class"))
> 
> (defmacro new-class ()
>   '(eval-when (:compile-toplevel :load-toplevel :execute)
>     (print "loading java class")
>     (def-java-class)))
> 
> compiling a file that has (new-class) in it gives
> 
> "loading java class" 
> "expanding def-java-class" 
> "executing def-java-class" 
> 
> and loading the compiled file gives
> 
> "loading java class" 
> "executing def-java-class" 
> 
> in both SBCL and ABCL, which is good, but is this order guaranteed? 
> But if I evaluate (new-class) in the REPL, I get
> 
> CL-USER> (new-class)
> 
> "expanding def-java-class" 
> "loading java class" 
> "executing def-java-class" 
> 
> in ABCL, and that's the problem. If this is an ABCL bug, I'd be happy
> to pass on the relevant chapter and verse from CLHS to Peter Graves,
> but I'd be surprised. 

Shrug.  We need and eval-when expert.

In LispWorks it preserves the order:

CL-USER 7 > (new-class)

"loading java class"
"expanding def-java-class"
"executing def-java-class"
"executing def-java-class"

CL-USER 8 > (load "lww/new-class.lisp")
; Loading text file d:\user\wade\lww\new-class.lisp

"loading java class"
"expanding def-java-class"
"executing def-java-class"
#P"d:/user/wade/lww/new-class.lisp"

CL-USER 9 > (compile-file "lww/new-class.lisp")
;;; Compiling file lww/new-class.lisp ...
;;; Safety = 3, Speed = 1, Space = 1, Float = 1, Interruptible = 0
;;; Compilation speed = 1, Debug = 2, Fixnum safety = 3, GC safety = 3
;;; Source level debugging is on
;;; Source file recording is  on
;;; Cross referencing is on
; (TOP-LEVEL-FORM 1)
; DEF-JAVA-CLASS
; NEW-CLASS

"loading java class"
; (TOP-LEVEL-FORM 2)

"expanding def-java-class"
"executing def-java-class"
; (TOP-LEVEL-FORM 3)
; (TOP-LEVEL-FORM 4)
#P"d:/user/wade/lww/new-class.fsl"
NIL
NIL

CL-USER 10 > (load "lww/new-class.fsl")
; Loading fasl file d:\user\wade\lww\new-class.fsl

"loading java class"
"executing def-java-class"
#P"d:/user/wade/lww/new-class.fsl"

CL-USER 11 >

 From the Hyperspec it says that :execute processes the forms as an
implicit progn.

http://www.lispworks.com/reference/HyperSpec/Body/s_eval_w.htm#eval-when

Wade
From: Andras Simon
Subject: Re: delaying macroexpansion
Date: 
Message-ID: <vcdsma39mu5.fsf@csusza.math.bme.hu>
Wade Humeniuk <····································@telus.net> writes:

> 
> Shrug.  We need and eval-when expert.

Agreed, on both counts.

> 
> In LispWorks it preserves the order:

In SBCL, too. But that probably doesn't mean a thing, because the
question really is how much latitude an implementation has in deciding
when to expand macros.
 
>  From the Hyperspec it says that :execute processes the forms as an
> implicit progn.
> 
> http://www.lispworks.com/reference/HyperSpec/Body/s_eval_w.htm#eval-when

Yes, but does the HS say anywhere that in a progn expansion happens in
order?  Wouldn't a compiler-only implementation be expected to expand
macros in a progn as part of the compilation process, before executing
anything?

Andras
From: Peter Seibel
Subject: Re: delaying macroexpansion
Date: 
Message-ID: <m3pt57b14u.fsf@javamonkey.com>
Andras Simon <······@math.bme.hu> writes:

> Yes, but does the HS say anywhere that in a progn expansion happens
> in order? Wouldn't a compiler-only implementation be expected to
> expand macros in a progn as part of the compilation process, before
> executing anything?

I think his is the relevant bit of the spec, from 3.2.3.1:

  However, the order of processing (including macro expansion) of
  subforms that are not top level forms and the order of further
  compilation is unspecified as long as Common Lisp semantics are
  preserved.

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Rob Warnock
Subject: Re: delaying macroexpansion
Date: 
Message-ID: <v8-dnYNcNcDMr6jcRVn-gg@speakeasy.net>
Peter Seibel  <·····@javamonkey.com> wrote:
+---------------
| Andras Simon <······@math.bme.hu> writes:
| > Yes, but does the HS say anywhere that in a progn expansion happens
| > in order? Wouldn't a compiler-only implementation be expected to
| > expand macros in a progn as part of the compilation process, before
| > executing anything?
| 
| I think his is the relevant bit of the spec, from 3.2.3.1:
| 
|   However, the order of processing (including macro expansion) of
|   subforms that are not top level forms and the order of further
|   compilation is unspecified as long as Common Lisp semantics are
|   preserved.
+---------------

Uh... If you're talking about top-level PROGNs, note that the part
you quote is part #6, which starts with the word "Otherwise..."
But earlier in 3.2.3.1 is this part, which overrides the "otherwise":

    3. If the form is a PROGN form, each of its body forms is
       sequentially processed as a top level form in the same
       processing mode.


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Peter Seibel
Subject: Re: delaying macroexpansion
Date: 
Message-ID: <m3sma27la5.fsf@javamonkey.com>
····@rpw3.org (Rob Warnock) writes:

> Peter Seibel  <·····@javamonkey.com> wrote:
> +---------------
> | Andras Simon <······@math.bme.hu> writes:
> | > Yes, but does the HS say anywhere that in a progn expansion happens
> | > in order? Wouldn't a compiler-only implementation be expected to
> | > expand macros in a progn as part of the compilation process, before
> | > executing anything?
> | 
> | I think his is the relevant bit of the spec, from 3.2.3.1:
> | 
> |   However, the order of processing (including macro expansion) of
> |   subforms that are not top level forms and the order of further
> |   compilation is unspecified as long as Common Lisp semantics are
> |   preserved.
> +---------------
>
> Uh... If you're talking about top-level PROGNs, 

No, we're talking about non-top-level PROGNs.

> note that the part you quote is part #6, which starts with the word
> "Otherwise..." But earlier in 3.2.3.1 is this part, which overrides
> the "otherwise":
>
>     3. If the form is a PROGN form, each of its body forms is
>        sequentially processed as a top level form in the same
>        processing mode.

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Rob Warnock
Subject: Re: delaying macroexpansion
Date: 
Message-ID: <uY6dnV1lYvFgp6jcRVn-sQ@speakeasy.net>
Peter Seibel  <·····@javamonkey.com> wrote:
+---------------
| ····@rpw3.org (Rob Warnock) writes:
| > Uh... If you're talking about top-level PROGNs, 
| 
| No, we're talking about non-top-level PROGNs.
+---------------

Oops! Sorry. (*blush*)   "Never mind..."


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Andras Simon
Subject: Re: delaying macroexpansion
Date: 
Message-ID: <vcdoekqan3m.fsf@csusza.math.bme.hu>
Peter Seibel <·····@javamonkey.com> writes:

> Andras Simon <······@math.bme.hu> writes:
> 
> > Yes, but does the HS say anywhere that in a progn expansion happens
> > in order? Wouldn't a compiler-only implementation be expected to
> > expand macros in a progn as part of the compilation process, before
> > executing anything?
> 
> I think his is the relevant bit of the spec, from 3.2.3.1:
> 
>   However, the order of processing (including macro expansion) of
>   subforms that are not top level forms and the order of further
>   compilation is unspecified as long as Common Lisp semantics are
>   preserved.

Yes, this probably settles the question (i.e., eval-when won't solve
my original problem). But I think that a similar remark should apply
to top level forms, too, at least as far as macro expansion is
concerned. 

(defmacro foo () (print "expanding"))
(progn (print "executing") (foo))

=> 

"expanding"
"executing"

should be OK, by the reasoning in your other post.

Andras
From: Peter Seibel
Subject: Re: delaying macroexpansion
Date: 
Message-ID: <m37jrfcggh.fsf@javamonkey.com>
Andras Simon <······@math.bme.hu> writes:

> The expansion of def-java-class is dependent on the Java environment
> (the superclass of the class NEW-CLASS is defining may have more or
> less methods, and that affects what def-java-class expands into).
> But that doesn't seem like a big problem. What does is that it's not
> clear to me how eval-when controls macro-expansion in this case.
> E.g., given
>
> (defmacro def-java-class () 
>   (print "expanding def-java-class") 
>   '(print "executing def-java-class"))
>
> (defmacro new-class ()
>   '(eval-when (:compile-toplevel :load-toplevel :execute)
>     (print "loading java class")
>     (def-java-class)))
>
> compiling a file that has (new-class) in it gives
>
> "loading java class" 
> "expanding def-java-class" 
> "executing def-java-class" 
>
> and loading the compiled file gives
>
> "loading java class" 
> "executing def-java-class" 
>
> in both SBCL and ABCL, which is good, but is this order guaranteed? 

I think yes, because EVAL-WHEN, will process its body as top-level
forms and (from 3.2.3.1):

  top level forms are processed in the order in which they textually
  appear in the file and that each top level form read by the compiler
  is processed before the next is read.

> But if I evaluate (new-class) in the REPL, I get
>
> CL-USER> (new-class)
>
> "expanding def-java-class" 
> "loading java class" 
> "executing def-java-class" 
>
> in ABCL, and that's the problem. If this is an ABCL bug, I'd be happy
> to pass on the relevant chapter and verse from CLHS to Peter Graves,
> but I'd be surprised. 

I think in this situation, since the call to new-class isn't occuring
as a top-level form (i.e. it's not in a file being processed by
compile-file) it's the :execute situation of the EVAL-WHEN which
controls what happens. In which case "the body forms are processed as
an implicit progn". Presumably if the implementation works by
compiling an expression and then excuting the compiled code all the
macro calls (such as to def-java-class) are going to be expanded
first, as you see here. So, as I read it, no bug in ABCL.

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Jeff Caldwell
Subject: Re: delaying macroexpansion
Date: 
Message-ID: <lzdZc.4086$NC6.1454@newsread1.mlpsca01.us.to.verio.net>
...
> > Andras Simon wrote:
> > > I'm trying to write a macro NEW-CLASS for abcl that creates a Java
> > > class (at load time), and defines a lispy interface to it using jfli's
> > > DEF-JAVA-CLASS macro. The problem is that DEF-JAVA-CLASS's expansion
> > > depends on the class it is called for, which is not available at
> > > compile-time. At present I delay the expansion like this
> > > (defmacro new-class (...)
> > > ...
> > >   `(progn     ;;JRC is the function that creates/loads the Java class
> > >     (jrc ,class-name ,super-name ,interfaces ...)
> > >     (funcall #'(lambda () (def-java-class ,class-name))))))))
> > > and it works, but I'm almost sure that that is accidental.
> >
> > I am not exactly sure what the problem is, but I think its that
> > until jrc is actually called def-java-class cannot be expanded
...

In the same category of jfli issues, as you pointed out, def-java-class uses
Java reflection and the JVM must be available for def-java-class to use. I
do this:

(eval-when (:compile-toplevel :load-toplevel :execute)
  (defun start-jfli ()
    (setq jfli-lisp::*jni-lib-path*
"c:\\sun\\appserver\\jdk\\jre\\bin\\client\\jvm.dll")
    (jfli-lisp::create-jvm (concatenate 'string
                                        "-Djava.class.path="

"c:\\lisp\\projects\\jfli\\jfli\\jfli.jar;"
                                        "c:\\java\\jface.jar;"
                                        "c:\\java\\runtime.jar;"
                                        "c:\\java\\swt.jar;"
                                        "c:\\java\\workbench.jar;"
                                        (foreign-classpath))
                           (concatenate 'string
                                        "-Djava.library.path="

"c:\\eclipse\\plugins\\org.eclipse.swt.win32_3.1.0\\os\\win32\\x86\\")))

  ; Start the JVM, which is needed to compile the rest of the code
  (cond (jni:*pvm* ; See jfli/jni.lisp create-jvm
         (princ "JVM already started"))
        (t (princ "Starting the JVM")
           (start-jfli)
           (enable-java-proxies))))

After that, a def-java-class at top level will work at compile time.

I can't tell exactly from your post but since "egrep -irl jrc *" returns
nothing in my jfli directory, I'm assuming that jrc is your own
function/macro and that it cannot do its work until load time. Wade
mentioned eval-when and I, too, want to understand eval-when better. My
little test shows (LWW):

(print "toplevel beginning of file")
(defun my-func ()
  (print "my-func executing"))
(eval-when (:compile-toplevel :load-toplevel :execute)
  (print "compile-toplevel load-toplevel execute, just printing this
message"))
(eval-when (:compile-toplevel)
  (print "compile-toplevel only"))
(eval-when (:load-toplevel)
  (print "load-toplevel only"))
(eval-when (:execute)
  (print "execute only"))
(eval-when (:compile-toplevel)
  (print "compile-toplevel calling my-func")
  (my-func))
(eval-when (:load-toplevel)
  (print "load-toplevel calling my-func")
  (my-func))
(eval-when (:execute)
  (print "execute calling my-func")
  (my-func))
(eval-when (:compile-toplevel :load-toplevel :execute)
  (print "compile-toplevel load-toplevel execute calling my-func")
  (my-func))


CL-USER 8 > (compile-file "c:/lisp/projects/jeff/eval-test.lisp")
;;; Compiling file c:/lisp/projects/jeff/eval-test.lisp ...
...
; (TOP-LEVEL-FORM 1)
; (TOP-LEVEL-FORM 2)
; MY-FUNC                           ;;;; <===  NOTE1

"compile-toplevel load-toplevel execute, just printing this message"
; (TOP-LEVEL-FORM 3)

"compile-toplevel only"
; (TOP-LEVEL-FORM 4)

"compile-toplevel calling my-func"

**++++ Error between functions:
  Undefined function MY-FUNC called with arguments ().
; (TOP-LEVEL-FORM 5)
; (TOP-LEVEL-FORM 6)

"compile-toplevel load-toplevel execute calling my-func"
; (TOP-LEVEL-FORM 7)


**++++ Error between functions:
  Undefined function MY-FUNC called with arguments ().
; (TOP-LEVEL-FORM 8)
; *** 2 errors detected, no fasl file produced.
NIL
((NIL #<UNDEFINED-FUNCTION 20687034> #<UNDEFINED-FUNCTION 20694D14>))
T

NOTE1 -- the compiler saw MY-FUNC and reported on it but MY-FUNC isn't
available for forms executing at :compile-toplevel. It's as if the compiler
is making two passes, with the first pass picking up only the
:compile-toplevel code. (The analogy isn't complete. I would depend on a
:compile-toplevel definition from the bottom of the file being available at
the top of the file...)

Notice that the only print's that executed were :compile-toplevel. I wrap
my-func in an eval-when:

(eval-when (:compile-toplevel)
  (defun my-func ()
    (print "my-func executing")))

and compile again.

"compile-toplevel calling my-func"
"my-func executing"
; (TOP-LEVEL-FORM 5)

The file compiles and my-func executes in the eval-whens.

CL-USER 14 > (load "c:/lisp/projects/jeff/eval-test")
; Loading fasl file c:\lisp\projects\jeff\eval-test.fsl

"toplevel beginning of file"
"compile-toplevel load-toplevel execute, just printing this message"
"load-toplevel only"
"load-toplevel calling my-func"
"my-func executing"
"compile-toplevel load-toplevel execute calling my-func"
"my-func executing"
#P"c:/lisp/projects/jeff/eval-test.fsl"

So the top-level forms execute during the load. MY-FUNC was wrapped in a
:compile-toplevel, without :load-toplevel or :execute, but MY-FUNC still
executed OK when the file was loaded. The DEFUN carried through and was
retained in the load-time image.

Now I 'rm eval-test.fsl' and:

CL-USER 15 > (load "c:/lisp/projects/jeff/eval-test")
; Loading text file c:\lisp\projects\jeff\eval-test.lisp

"toplevel beginning of file"
"compile-toplevel load-toplevel execute, just printing this message"
"execute only"
"execute calling my-func"
"my-func executing"
"compile-toplevel load-toplevel execute calling my-func"
"my-func executing"
#P"c:/lisp/projects/jeff/eval-test.lisp"

Now everything is "execute".

:compile-toplevel runs during the compile, :load-toplevel runs when a
compiled fasl file is loaded, and :execute runs when a .lisp source file is
loaded. (Does this mean that "execute" is done only in an interpretive
environment? I see what's happening in my example but I certainly don't
grasp the implications of why.)

In any event, if you get the JVM running at :compile-toplevel,
:load-toplevel, and :execute (possibly in a separate file that ASDF can
ensure is loaded before the subsequent ones, if order of execution is an
issue), I wonder if wrapping your 'jrc' followed by 'def-java-class' calls
in :load-toplevel :execute eval-when's will fix your problem?

Jeff
From: Jeff Caldwell
Subject: Re: delaying macroexpansion
Date: 
Message-ID: <1KdZc.4091$NC6.1175@newsread1.mlpsca01.us.to.verio.net>
Geeze -- the power of a missing word. I meant I would NOT depend ....


"Jeff Caldwell" <·········@yaSPhooAM.com> wrote in message news:lzdZc.4086
...
> NOTE1 -- the compiler saw MY-FUNC and reported on it but MY-FUNC isn't
> available for forms executing at :compile-toplevel. It's as if the
compiler
> is making two passes, with the first pass picking up only the
> :compile-toplevel code. (The analogy isn't complete. I would depend on a

^^^^^^^^^^
> :compile-toplevel definition from the bottom of the file being available
at
> the top of the file...)
...

Since I'm here again anyway, and since what def-java-class actually does may
impact the discussion, here is what def-java-class actually does. MY-ME is
my macroexpand, which expands more than just the outermost form.

JFLI-LISP 27 > (pprint (my-me '(def-java-class
"org.eclipse.jface.window.ApplicationWindow")))

(LOCALLY
  (JFLI::ENSURE-PACKAGE "org.eclipse.jface.window")
  (DEFCONSTANT |org.eclipse.jface.window|:APPLICATIONWINDOW. (QUOTE

|org.eclipse.jface.window|::|ApplicationWindow|))
  (EXPORT '|org.eclipse.jface.window|:APPLICATIONWINDOW.
          (SYMBOL-PACKAGE '|org.eclipse.jface.window|:APPLICATIONWINDOW.))
  (LOCALLY
    (DEFUN |org.eclipse.jface.window|:APPLICATIONWINDOW.NEW (&REST
JFLI::ARGS)

"org.eclipse.jface.window.ApplicationWindow(org.eclipse.swt.widgets.Shell)
"
      (APPLY #'JFLI::INSTALL-CONSTRUCTORS-AND-CALL
             "org.eclipse.jface.window.ApplicationWindow"
             JFLI::ARGS))
    (EXPORT '|org.eclipse.jface.window|:APPLICATIONWINDOW.NEW
            (SYMBOL-PACKAGE
'|org.eclipse.jface.window|:APPLICATIONWINDOW.NEW))
    (DEFMETHOD MAKE-NEW
      ((JFLI::CLASS-SYM (EQL |org.eclipse.jface.window|:APPLICATIONWINDOW.))
       &REST
       JFLI::ARGS)
      (APPLY #'|org.eclipse.jface.window|:APPLICATIONWINDOW.NEW
JFLI::ARGS)))
  (LOCALLY
    (DEFUN |org.eclipse.jface.window|:APPLICATIONWINDOW.TOSTRING (&REST
JFLI::ARGS)
      "java.lang.String toString()
"
      (APPLY #'JFLI::INSTALL-METHODS-AND-CALL
             "org.eclipse.jface.window.ApplicationWindow"
             "toString"
             JFLI::ARGS))
    (EXPORT '|org.eclipse.jface.window|:APPLICATIONWINDOW.TOSTRING
            (SYMBOL-PACKAGE
'|org.eclipse.jface.window|:APPLICATIONWINDOW.TOSTRING))
    (DEFUN |org.eclipse.jface.window|:APPLICATIONWINDOW.NOTIFYALL (&REST
JFLI::ARGS)
      "void notifyAll()
"
      (APPLY #'JFLI::INSTALL-METHODS-AND-CALL
             "org.eclipse.jface.window.ApplicationWindow"
             "notifyAll"
             JFLI::ARGS))
    (EXPORT '|org.eclipse.jface.window|:APPLICATIONWINDOW.NOTIFYALL
            (SYMBOL-PACKAGE
'|org.eclipse.jface.window|:APPLICATIONWINDOW.NOTIFYALL))

... <many similar definitions deleted>

    (DEFINE-SYMBOL-MACRO
|org.eclipse.jface.window|:*APPLICATIONWINDOW.CANCEL*

(|org.eclipse.jface.window|:APPLICATIONWINDOW.CANCEL))
    (EXPORT '|org.eclipse.jface.window|:*APPLICATIONWINDOW.CANCEL*
            (SYMBOL-PACKAGE
'|org.eclipse.jface.window|:*APPLICATIONWINDOW.CANCEL*)))
  (DEFCLASS |org.eclipse.jface.window|:APPLICATIONWINDOW.
            (|org.eclipse.jface.operation|::IRUNNABLECONTEXT.
             |org.eclipse.jface.window|::WINDOW.)
            NIL))
From: Thomas A. Russ
Subject: Re: delaying macroexpansion
Date: 
Message-ID: <ymid616c4eq.fsf@sevak.isi.edu>
Andras Simon <······@math.bme.hu> writes:
> compiling a file that has (new-class) in it gives
> 
> "loading java class" 
> "expanding def-java-class" 
> "executing def-java-class" 
> 
> and loading the compiled file gives
> 
> "loading java class" 
> "executing def-java-class" 
> 
> in both SBCL and ABCL, which is good, but is this order guaranteed? 
> But if I evaluate (new-class) in the REPL, I get
> 
> CL-USER> (new-class)
> 
> "expanding def-java-class" 
> "loading java class" 
> "executing def-java-class" 
> 
> in ABCL, and that's the problem. If this is an ABCL bug, I'd be happy
> to pass on the relevant chapter and verse from CLHS to Peter Graves,
> but I'd be surprised. 
> 
> Andras

You would do well to try this in LispWorks.  In the past, I have noticed
that LispWorks tends to do macroexpansion and top-level progn handling a
little differently than other Lisp systems.  I'm pretty sure that the
LispWorks scheme is conformant to the standard, but since it is a
different design point in the allowed implementation space, it can
sometimes cause problems if the precise timing of expansion and
evaluation is critical to the application.


-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Andras Simon
Subject: Re: delaying macroexpansion
Date: 
Message-ID: <vcdfz61akvr.fsf@csusza.math.bme.hu>
···@sevak.isi.edu (Thomas A. Russ) writes:

> 
> You would do well to try this in LispWorks.  In the past, I have noticed
> that LispWorks tends to do macroexpansion and top-level progn handling a
> little differently than other Lisp systems.  I'm pretty sure that the
> LispWorks scheme is conformant to the standard, but since it is a
> different design point in the allowed implementation space, it can
> sometimes cause problems if the precise timing of expansion and
> evaluation is critical to the application.

No surprises there: 

CL-USER> (new-class)

"loading java class" 
"expanding def-java-class" 
"executing def-java-class" 
"executing def-java-class"
CL-USER> 

Of the implementations I tried (SBCL, CMUCL, LW, ABCL), only ABCL does
the expansion first. And I think it has the right to do so. 

Andras