[comp.emacs] defmacro vs. defun

tjo@dasher.siemens.com (Tom Ostrand) (07/15/88)

I've just experienced the same problems with byte-compiling 
Elisp code that uses macros, as described in some recent 
postings.
Only difference was that the macros were defined in file A, and
used in File B.
The compiled code of file B set up function call sequences for the
macros if file A had not yet been loaded.  Then the compiled code
hangs when it tries to "call" the macro.

Question: How much is really saved by defining a macro instead of a 
function? The macros that caused the trouble were caar, cadr, cdar, etc.
Also, for these simple macros, how much MORE would be saved by just 
writing out (car (car ...) ) instead of caar?

liberte@m.cs.uiuc.edu (07/16/88)

[ /* Written 10:33 am  Jul 15, 1988 by tjo@dasher.siemens.com in m.cs.uiuc.edu:comp.emacs */
[ /* ---------- "defmacro vs. defun" ---------- */
[ The compiled code of file B set up function call sequences for the
[ macros if file A had not yet been loaded.  Then the compiled code
[ hangs when it tries to "call" the macro.

Consider yourself lucky if you call the macro in such a way that it fails
to byte-compile.  It can be difficult to track down the problem otherwise.

[ Question: How much is really saved by defining a macro instead of a 
[ function? The macros that caused the trouble were caar, cadr, cdar, etc.
[ Also, for these simple macros, how much MORE would be saved by just 
[ writing out (car (car ...) ) instead of caar?

If not byte-compiled, a macro call must be expanded every time
it is seen.  This will definitely take longer since the
macro call is essentially a call to the macro as if it were a function
followed by evaluation of the result.  If byte-compiled, there is no
penelty since the expansion is done (if it is known as a macro) at
compile time.

Dan LaLiberte
uiucdcs!liberte
liberte@cs.uiuc.edu
liberte%a.cs.uiuc.edu@uiucvmd.bitnet

Ram-Ashwin@cs.yale.edu (Ashwin Ram) (07/18/88)

In article <4300016@m.cs.uiuc.edu>, liberte@m writes:
> [ Question: How much is really saved by defining a macro instead of a 
> [ function? The macros that caused the trouble were caar, cadr, cdar, etc.
> [ Also, for these simple macros, how much MORE would be saved by just 
> [ writing out (car (car ...) ) instead of caar?
> 
> If not byte-compiled, a macro call must be expanded every time
> it is seen.  This will definitely take longer since the
> macro call is essentially a call to the macro as if it were a function
> followed by evaluation of the result.  If byte-compiled, there is no
> penelty since the expansion is done (if it is known as a macro) at
> compile time.

This is correct, but I think Tom's question was really, why use macros at all
instead of either writing out the code, or using a function instead?  Using the
(caar ...) macro is exactly the same as (car (car ...)) in terms of efficiency
once the macro has been expanded.  In EL, this happens during byte-compilation,
but it could, and in many other Lisps it does, happen at definition time, even
in interpreted code.

Given this, the main reasons for using macros are:

- to reduce code clutter and improve readability.  E.g., (caar ...) is more
readable than (car (car ...)).  This gets more obvious for bigger macros.

- to save the time required for a function call.  E.g., (caar ...) defined as a
macro is more efficient than (caar ...) defined as a function, because in the
latter case you have to call and return from the caar function.

- to introduce new special forms.

Perhaps there should be a way to declare autoload's for macros, such that the
byte-compiler would do the autoload before compilation, just like eval does
before evaluation?

-- Ashwin.

ARPA:    Ram-Ashwin@cs.yale.edu
UUCP:    {decvax,ucbvax,harvard,cmcl2,...}!yale!Ram-Ashwin
BITNET:  Ram@yalecs

rlk@think.com (Robert Krawitz) (07/18/88)

In article <33735@yale-celray.yale.UUCP>, Ram-Ashwin@cs (Ashwin Ram) writes:

]Perhaps there should be a way to declare autoload's for macros, such that the
]byte-compiler would do the autoload before compilation, just like eval does
]before evaluation?

That's what require is for.  Autoloads aren't a particularly standard
part of lisp, and in emacs lisp they're primarily for use with
interactive commands, not internal lisp code.  The byte compiler
respects requires in files, so you can load in macro definitions.  I
suspect that putting a (require 'cl) followed by a (provide 'cl) at
the top of the cl.el file would solve the compilation problems with
that file (of course, the correct solution is to eliminate the
dependencies by ensuring that all macros are defined before they are
referenced).  I use require and provide for all packages that I write
that consist of multiple files, as emacs lisp doesn't have anything
like make, or systems, or the like (although I'm slowly working on
this, so stay tuned).

We actually did implement a vdefun (virtual defun, which is basically
an autoload) for common lisp around here, but we don't use it all that
much.  In fact, the only common use for it around here is
interactively loading Connection Machine software into a lisp world,
which is more in line with how Emacs Lisp normally uses autoloads.
-- 
harvard >>>>>>  |		Robert Krawitz <rlk@think.com>
bloom-beacon >  |think!rlk
topaz >>>>>>>>  .		rlk@a.HASA.disorg

gore@eecs.nwu.edu (Jacob Gore) (07/21/88)

/ comp.emacs / rlk@think.com (Robert Krawitz) / Jul 18, 1988 /
>I suspect that putting a (require 'cl) followed by a (provide 'cl) at the 
>top of the cl.el file would solve the compilation problems with that file

Won't that cause cl.el to load itself in infinitely?

Jacob Gore				Gore@EECS.NWU.Edu
Northwestern Univ., EECS Dept.		{oddjob,gargoyle,att}!nucsrl!gore

rlk@think.com (Robert Krawitz) (07/23/88)

In article <3910019@eecs.nwu.edu>, gore@eecs (Jacob Gore) writes:
]/ comp.emacs / rlk@think.com (Robert Krawitz) / Jul 18, 1988 /
]>I suspect that putting a (require 'cl) followed by a (provide 'cl) at the 
]>top of the cl.el file would solve the compilation problems with that file
]
]Won't that cause cl.el to load itself in infinitely?

Hmm.  Probably will, at that.  So much for that idea...
-- 
harvard >>>>>>  |		Robert Krawitz <rlk@think.com>
bloom-beacon >  |think!rlk
topaz >>>>>>>>  .		rlk@a.HASA.disorg

weemba@garnet.berkeley.edu (Matthew P Wiener) (07/23/88)

In article <24364@think.UUCP>, rlk@think (Robert Krawitz) writes:
>In article <3910019@eecs.nwu.edu>, gore@eecs (Jacob Gore) writes:
>]>I suspect that putting a (require 'cl) followed by a (provide 'cl) at the
>]>top of the cl.el file would solve the compilation problems with that file
>]Won't that cause cl.el to load itself in infinitely?
>Hmm.  Probably will, at that.  So much for that idea...

Try

(condition-case nil (require 'cl) (error))
(provide 'cl)

instead.

ucbvax!garnet!weemba	Matthew P Wiener/Brahms Gang/Berkeley CA 94720

merlyn@intelob (Randal L. Schwartz @ Stonehenge) (07/26/88)

In article <12443@agate.BERKELEY.EDU>, weemba@garnet (Matthew P Wiener) writes:
| In article <24364@think.UUCP>, rlk@think (Robert Krawitz) writes:
| >In article <3910019@eecs.nwu.edu>, gore@eecs (Jacob Gore) writes:
| >]>I suspect that putting a (require 'cl) followed by a (provide 'cl) at the
| >]>top of the cl.el file would solve the compilation problems with that file
| >]Won't that cause cl.el to load itself in infinitely?
| >Hmm.  Probably will, at that.  So much for that idea...
| 
| Try
| 
| (condition-case nil (require 'cl) (error))
| (provide 'cl)
| 
| instead.


Or, as a little experimentation showed (yes, it is not intuitive, but
tested...):

  (provide 'cl)
  (require 'cl)

Reasons?  If file is loaded normally, the provide satisfies the require,
and hence no recursion.  If the file is byte-compiled without loading first,
the provide is ignored, but the require is eval-ed (scan bytecomp.el for
require for details), and the file gets loaded.  Cool, eh?

One version of (eval-when 'compile (FORM)) could be:

(require 'FooBar
	 (prog1
	     "/dev/null"
	   (provide 'FooBar)
	   (if load-in-progress
	       (y-or-n-p "WAS LOADING " )
	     (y-or-n-p "WAS COMPILING ")
	     )
	   )
	 )

where the WAS LOADING is executed at load time, and WAS COMPILING is
executed at compile time.  Yes, yes, yes, a hack, but it does work.
"FooBar" of course is your favorite random string.  This, of course,
does not work the second time around, but hey, its only Monday.

-- 
Randal L. Schwartz, Stonehenge Consulting Services (503)777-0095
on contract to BiiN Technical Publications (for now :-), Hillsboro, Oregon
<merlyn@intelob.intel.com> or ...!tektronix!ogcvax!omepd!intelob!merlyn
Standard disclaimer: I *am* my employer!