[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
proposal LOAD-TIME-EVAL:REVISED-NEW-SPECIAL-FORM
- To: sandra%defun@cs.utah.edu
- Subject: proposal LOAD-TIME-EVAL:REVISED-NEW-SPECIAL-FORM
- From: Jon L White <jonl@lucid.com>
- Date: Mon, 26 Sep 88 21:52:09 PDT
- Cc: cl-compiler@sail.stanford.edu, cl-cleanup@sail.stanford.edu
- In-reply-to: Sandra J Loosemore's message of Mon, 19 Sep 88 14:06:15 MDT <8809192006.AA00963@defun.utah.edu>
Of the numerous proposals of this ilk, this one seems to me to be the one
most workable.
Following our charter, we should look to Interlisp and see how experience
has fared with its function LOADTIMECONSTANT [maybe never documented?].
Its semantics were, coincidentally, essentially the same as those you have
spelled out for LOAD-TIME-EVAL. [By the way, shouldn't the Interlisp
precedent bias us towards the name LOAD-TIME-CONSTANT rather than towards
LOAD-TIME--EVAL?].
However, a more serious issue seems to have gotten lost in all the flaming.
At Lucid, we all seem to favor flushing #,. Who really wants it? At best,
when someone previously suggested flushing #, I remember an efficiency
argument being invoked, but not being _demonstrated_.
There is a serious flaw in the design of #, and for this reason alone
it should be flushed [explication of the "flaw" is further below.] The
burden of _proof_ to show that any reasonable program is seriously
hampered without it is on those who invoke the argument. As Gabriel
would say of benchmarking, no raw numbers without theory to explain why,
and certainly no speculation without hard numbers.
Where are the numbers which prove an inefficiency so grave as to cause
us to tolerate this inherently flawed and misleading construct #,?
The "grave flaw" centers around the common misconception that you
are either:
(1) reading the source code, for interpretation -- EVAL situation
(2) reading it for compilation to a file -- COMPILE situation
(3) loading the compiled version of the file -- LOAD situation
that is, one and only one of the three situations applies. But as Kent's
little trivial example showed:
(EVAL-WHEN (EVAL COMPILE LOAD)
(DEFUN FOO (X) #,`(X ,(SQRT 3))))
you may be reading a piece of code for *** two *** of the situations at
one time. You are both EVAL'ing and COMPILE'ing a single solitary form
at essentially "one and the same time". [Early versions of PCL tried to
use some such trick, and lost badly.]
The whole idea of the "magic token" is that at read-time you can somehow
inspect either the dynamic or lexical environment, and decide with of the
three situations is relevant. But you can't; you can only know which
situation is relevant at actual processing time -- not at read time (and
of course a special form has access to the lexical environment). Sandra
put it quite well when countering a proposal to make the LOAD-TIME-EVAL
thing be a function instead of a special form:
Date: Wed, 21 Sep 88 15:05:28 MDT
Subject: Re: Issue: LOAD-TIME-EVAL (Version 6)
. . .
there a[re] more situations in which code is processed than simply
interpretation and compilation. It is not an either/or situation. A
person here at the UofU, for example, has been working on a portable
type inference preprocessor. It reads in code, decorates it with lots
of type declarations, and writes it out to another file which may then
either be loaded interpretively or compiled with COMPILE-FILE. . . .
The implications of these theoretical arguments are not always easy to
follow, so I have reproduced an example file below that helps one see
just how the screw-up occurs. Every implementation I've tried this file
in, when the source is loaded, "does the right thing". But when it is
compiled, they all leave the "magic tokens" in the source code for the
function 'expose'; so the value of 'foo', after compilation, has these
tokens in it rather than the desired structure ((COMPILE A) (COMPILE B)).
Correspondingly, the value of 'bar' -- the 'exposure-normality' of 'foo'
-- is ABNORMAL.
Worse yet, because the definition of 'normally-exposed-p' is a macro that
gets "snapped" at compile time, the error is propagated to the runtime
setting of 'bar'. Namely, when the compiled file is loaded, 'foo' has
the right value -- ((LOAD A) (LOAD B)) -- but 'bar' wrongly says that
the 'exposure-normality' state is ABNORMAL. [Well, one implementation
got the value of 'foo' wrong too, but, hey, what the heck.]
Take this example and try it. Look at FOO and BAR after each pass.
You'll dislike it! Flush #,.
-- JonL --
;;;--------------------------------------------------------------------------
(in-package "USER")
;;; Clean the slate, in case this isn't "first time" processing
(eval-when (eval compile load)
(fmakunbound 'expose)
(fmakunbound 'exposure-normality)
(proclaim '(special markers))
)
;;; Use different marker depending on which situation is relevant.
(eval-when (eval)
(setq markers '((eval a) (eval b) (eval c)))
)
(eval-when (compile)
(setq markers '((compile a) (compile b) (compile c)))
)
(eval-when (load)
(setq markers '((load a) (load b) (load c)))
)
(eval-when (eval compile load)
(defun expose ()
`(#,(pop markers) #,(pop markers)))
(defmacro exposure-normality ()
(if (member (car (expose))
'((eval a) (compile a) (load a))
:test #'equal)
`'normal
`'abnormal))
)
(eval-when (eval compile load)
(defparameter foo (expose))
(defparameter bar (exposure-normality))
)
;;;--------------------------------------------------------------------------