From: Arseny Slobodjuck
Subject: 'Autocompiled' function
Date: 
Message-ID: <3badd900.24688920@news.vtc.ru>
Hi, 

Is it legal to define such a macro ? It expands to nothing, but have
several useful side-effects. Question mainly about using defmacro as
procedure not evaluating it's params.

(defparameter  *compiled-defs* ())

(defmacro defcompf(name args &rest body)
  (push name *compiled-defs*)
  (format t "~%;; Defined ~A" name)
  (eval `(defun ,name ,args ,@body))
  (compile name)
  nil)
  
  

From: Kent M Pitman
Subject: Re: 'Autocompiled' function
Date: 
Message-ID: <sfwbsk2qes4.fsf@world.std.com>
····@crosswinds.net (Arseny Slobodjuck) writes:

> Is it legal to define such a macro ?

You can write the code you wrote below, but it probably doesn't do what
you want.

> It expands to nothing, 

Right. That means your function will not be defined at load time.

> but have several useful side-effects.

In the compile-time environment only.

> Question mainly about using defmacro as procedure not evaluating
> it's params.
> 
> (defparameter  *compiled-defs* ())

The above variable will be defined only at load time of the file
containing this code.  That means the following definition will
push definitions onto the list when defcompf forms are seen,
but at load-time of the defcompf forms, *compiled-defs* will generally
be NIL (unless you load the definitions interpreted).

> (defmacro defcompf(name args &rest body)

Put a space before the "(" please.  The notation "word(...)" ought not occur
in Lisp code with good style.  That is, never juxtapos an open paren with
text to its left nor a close paren with text to its right without intervening
whitespace.

>   (push name *compiled-defs*)
>   (format t "~%;; Defined ~A" name)
>   (eval `(defun ,name ,args ,@body))
>   (compile name)
>   nil)

All in all, I recommend you NOT do this.  If you want your functions 
compiled, just compile them.

If you're really desperate to never run interpreted code (and I just 
don't understand your motivation), the right way to write the above is:

 (defmacro defcompf2 (name args &rest body)
   `(progn
      (defun ,name ,args ,@body)
      (eval-when (:execute) ;only when not compiling anyway
        (compile ',name))
      ',name))
From: Pierre R. Mai
Subject: Re: 'Autocompiled' function
Date: 
Message-ID: <87wv2qj5mx.fsf@orion.bln.pmsf.de>
····@crosswinds.net (Arseny Slobodjuck) writes:

> Hi, 
> 
> Is it legal to define such a macro ? It expands to nothing, but have
> several useful side-effects. Question mainly about using defmacro as
> procedure not evaluating it's params.

While it is legal to have macro-expanders that side-effect the
(compile-time/evaluation-time) environment, it is very, very hard to
do this in a way that is useful, because you don't get any form of
guarantee when exactly and how often the macro-expander is invoked for
a given form.  The compiler and the interpreter have much lee-way in
this regard (see the HyperSpec for details).  

Furthermore, other tools than the compiler and interpreter are allowed
to expand macros, e.g. code-walkers, sexp-counting or diff tools,
crossreferencing, metrics, etc. tools, and so on.

And finally you are only guaranteed that your side-effects will effect
the environment at macro-expansion time, and don't have any guarantees
that that environment is present at load or run-time.

With the given constraints, it is very, very hard to make side-effects
at macro-expansion do what is really wanted, reliably.  It is (almost?)
always preferable to use other mechanisms.

> (defparameter  *compiled-defs* ())
> 
> (defmacro defcompf(name args &rest body)
>   (push name *compiled-defs*)
>   (format t "~%;; Defined ~A" name)
>   (eval `(defun ,name ,args ,@body))
>   (compile name)
>   nil)

This particular macro-expander suffers from a number of problems, in
relation/addition to those mentioned above:

- It doesn't work correctly when invoked multiple times for a given
  form (multiple pushes of name, multiple formats, etc.).

- Just macro-expanding a form should never, ever effect that form.
  Just because I evaluate (macroexpand '(defun demo (x) (1+ x))),
  doesn't mean I want to compile and install a function named demo.
  If I wanted that, I'd eval (or compile and eval) the form.

- Compiling a file containing a defcompf form will compile and install
  the function (at macro-expansion time) in the compile-time
  environment.  Loading the compiled file into another image will not
  have any effect at all, since no macro-expansion will occur.  Both
  kinds of behaviour are really suspect.  There are only very few
  forms that should have effects on the compile-time environment
  outside of eval-when, mostly for convenience reasons (like defmacro
  itself).  There are very, very few forms, that outside of eval-when
  should only have compile-time effect, and no load-time effects.

  Definition forms should mostly follow the defun example, and only
  under special circumstances follow the defmacro example or that of
  other more intricate defining forms.

- The use of eval will cause the defun form to be evaluated/compiled
  in the null lexical-environment, whereas the correct way of letting
  the normal compiler compile the expansion will heed the lexical
  environment present at the point of the defcompf form:

  (let ((x 5))
    (defcompf foo (y) (+ x y)))

  should work as expected, but doesn't in your version.

The normal way of writing something like this would be:

(defparameter  *compiled-defs* '())

(defmacro defcompf (name args &rest body)
  `(progn
     (defun ,name ,args ,@body)
     (pushnew ',name *compiled-defs*)
     (format t "~%;; Defined ~A" ',name)))

If you really want the function and side-effects to also affect the
compile-time environment in the file-compiler, you can do

(defmacro defcompf (name args &rest body)
  `(eval-when (:compile-toplevel :load-toplevel :execute)
     (defun ,name ,args ,@body)
     (pushnew ',name *compiled-defs*)
     (format t "~%;; Defined ~A" ',name)))

However I don't see the reason for the format, since I really don't
think one wants this kind of output at load-time (whereas one really
wants the definition to also or solely take effect at load-time).  So
maybe the following is more useful:

(defmacro defcompf (name args &rest body)
  `(eval-when (:compile-toplevel :load-toplevel :execute)
     (defun ,name ,args ,@body)
     (pushnew ',name *compiled-defs*)
     (eval-when (:compile-toplevel :execute)
       (format t "~%;; Processed ~A" ',name))))

Regs, Pierre.

-- 
Pierre R. Mai <····@acm.org>                    http://www.pmsf.de/pmai/
 The most likely way for the world to be destroyed, most experts agree,
 is by accident. That's where we come in; we're computer professionals.
 We cause accidents.                           -- Nathaniel Borenstein
From: Arseny Slobodjuck
Subject: Re: 'Autocompiled' function
Date: 
Message-ID: <3bae6698.381959@news.vtc.ru>
Kent, Pierre, thank you for answers, I should think about load/compile
times more intensively. Actually I never think about compile-file
applied to file with this defcompf's. And I should think about
expression 'load time of the file'. This is as if files have good
times and bad times and also load times.
From: Sam Steingold
Subject: Re: 'Autocompiled' function
Date: 
Message-ID: <uwv2ok4oa.fsf@xchange.com>
CLISP has a declaration `compile' which forces compilation:

(defun foo (x)
  (declare (compile))
  ...)

#'foo ==> #<compiled-closure foo>

-- 
Sam Steingold (http://www.podval.org/~sds)
Support Israel's right to defend herself! <http://www.i-charity.com/go/israel>
Read what the Arab leaders say to their people on <http://www.memri.org/>
Those who can't write, write manuals.