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