Subject: Re: clisp: COMPILE-FILE needs two LOADs?
From: rpw3@rpw3.org (Rob Warnock)
Date: Thu, 23 Feb 2006 07:59:18 -0600
Newsgroups: comp.lang.lisp
Message-ID: <VYydnVWfMsorImDenZ2dnUVZ_sOdnZ2d@speakeasy.net>
Joerg Hoehle  <hoehle@users.sourceforge.net> wrote:
+---------------
| rpw3@rpw3.org (Rob Warnock) writes:
| >Thank goodness there's LOAD-TIME-VALUE...  ;-}
| 
| I'd appreciate if you could expand on that, as Edi also uses
| LOAD-TIME-VALUE in cl-ppcre.  E.g., I'm not clear I could use
| LOAD-TIME-VALUE in Iterate (which uses EVAL in one place...).
+---------------

I don't recall Iterate, so I'm not sure. But in CL-PPCRE it's
used to get around the very problem we were discussing -- symbols
defined with DEFCONSTANT can show up as CONSTANTP at compile time
(macro-expansion time, really) but the value might not be accessible
then. The use of LOAD-TIME-VALUE pushes the actual reference *and*
any possibly-expensive computation on it to load time, but ensures
that the calcuation is still only done once per LOAD. [Which is worse
than once per compilation, but still a lot better than, say, once
per trip around a tight loop].

Consider one of the uses in CL-PPCRE, and how Edi *might* have been
able to write it if the availability of the values of DEFCONSTANT
forms at compile time were mandated/guaranteed by the standard:

    (define-compiler-macro split (&whole form
				  regex target-string &rest rest)
      "Make sure that constant forms are compiled into scanners
      at compile time."
      (cond ((constantp regex)
	      `(split ,(create-scanner regex)
		      ,target-string ,@rest))
	    (t form)))

If the arg REGEX were a constant, the above version would evaluate
(CREATE-SCANNER REGEX) at macro-expansion [compile] time and embed
the resulting complex object as a quasi-literal in the generated
SPLIT call. But as we know from this thread, the values of DEFCONSTANT
forms are *not* guaranteed to be accessible to compile time, which
is why Edi wrote it like this instead:

    (define-compiler-macro split (&whole form
				  regex target-string &rest rest)
      "Make sure that constant forms are compiled into scanners
      at compile time."
      (cond ((constantp regex)
	      `(split (load-time-value (create-scanner ,regex))
		      ,target-string ,@rest))
	    (t form)))

Yes, this doesn't allow the CREATE-SCANNER call to occur at compile
time, but it *still* only calls it once, at load time, and not once
per call of SPLIT.

LOAD-TIME-VALUE can also work better than macro-expansion-time
evaluation when the functions being called in the LOAD-TIME-VALUE
expression don't exist at all in the compile time environment,
because of separate compilation, say, but *do* exist at load time
because of the order that the modules of the final application
are loaded.

Does that address your question adequately?


-Rob

-----
Rob Warnock			<rpw3@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607