[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Issue: LOAD-TIME-EVAL (Version 8)

This issue passed, but I still have a couple of things to say about it.
It may be that it needs a follow-up to fix it up a little and resolve
some remaining semantic problems.

    It is guaranteed that 
    the evaluation of <form> will take place only once when the file is 
    loaded, but the order of evaluation with respect to the "evaluation" 
    of top-level forms in the file is unspecified.

The second clause (order) is clearly wrong, since if a top-level form
contains a LOAD-TIME-EVAL, the load-time-eval must be evaluated no
later than when the evaluation of the top-level form reaches it.  Also
I don't see how the first clause (once-only) can be guaranteed when
the LOAD-TIME-EVAL appears inside a top-level loop, unless it's
guaranteed that the compiler fully searches top-level forms to all
levels to find all possible LOAD-TIME-EVAL forms.  Is it?

    Implementations must guarantee that each reference to a
    LOAD-TIME-VALUE expression results in at least one evaluation of its
    nested <form>.  For example,
    must perform two calls to COMPUTE-IT; although there is only one
    unique LOAD-TIME-VALUE expression, there are two distinct references
    to it.

I think this is not well-defined.  I don't have a written copy of your
amended version of this example, but I think it had the same problem.

Are the following examples one reference or two?


    (FLET ((F () (LOAD-TIME-VALUE (COMPUTE-IT)))) (F) (F))

      (F) (F))

      (F) (F))

  Similarly for "each call to EVAL must result in a new evaluation of <form>",
  what things can LOAD-TIME-VALUE be nested inside and still be guaranteed
  to cons fresh constants?  What about displacing macros?

These examples show that you can't use EQ on the LOAD-TIME-VALUE expression
nor on any single thing containing it as your definition of expression
identity.  In case you don't know what displacing macros are, they were
a Maclisp feature where the car and cdr of the macro call were replaced
by the car and cdr of the macro expansion, thus ensuring that the interpreter
only expanded a macro once.  In general this is not a safe optimization in
a system with lexical scoping, since the same (EQ) macro call might be
inserted by macro expansion into several different lexical environments,
and the correct macro expansion of that call might vary depending on the
lexical environment.  But it's still interesting as a way that the same
form can get into multiple places in a funny way.

If you didn't have the non-read-only case, then coalescing would be allowed
and you wouldn't have to try to define what a distinct reference to a
LOAD-TIME-VALUE expression is, since you wouldn't have to require that
each distinct reference gets evaluated.  I guess too many people like
the non-read-only case for it to be likely to go away.

I have not been able to think of any satisfactory solution to this
problem, but I do not think you can get away with leaving it as-is.  I
guess that the most likely route to a solution will involve defining
some sort of "tree walk" through the source code, defining the identity
of a form as the path taken through the tree to reach that form.  I'm
guessing that the intuition that the proposal intended to capture is the
same thing that this tree walk does.  This tree walk approach will run
into some significant difficulties with macros, but perhaps that's
tractable by defining it in terms of what EVAL does, somehow coping with
the multiple evaluations caused by looping and the missing evaluations
caused by conditionals.

Alternatively, you might abandon the intuition and think about the 
consequences of just using EQ of the LOAD-TIME-VALUE expression.  Would
it be so bad?

  I don't understand why the read-only-p argument isn't evaluated in the
  null lexical environment just like the form argument (instead of being
  an unevaluated argument).