From: jeff@aiai.edinburgh.ac.uk (Jeff Dalton)
Subject: Re: Generic Macro Proposal (really interpreted/compiled semantics)
Organization: The Ohio State University Department of Computer and Information Science
Date: Wed, 26 Aug 1992 17:04:15 GMT

> In article <10367.9208251621@subnode.aiai.ed.ac.uk> jeff@aiai.edinburgh.ac.uk (Jeff Dalton) writes:> 
> >> Since the above program isn't conforming, anything is legal. 
> >
> >If this is what the dpANS says, I think it should change.  
> 
> Actually, I think I was overstating it.  Perhaps I should have said, "since
> it isn't conforming, the standard doesn't specify which one it returns."

I've just been looking at the dpANS, and it seems to be fairly
reasonable in its treatment of conforming code.  For instance
in section 1.5.2.1 it's noted that conforming code can produce
different results in different conforming implementations.
There are examples such as

  (random)

  (evenp most-positive-fixnum)

However, this seems less strict (and more reasonable) than the part of
chapter 3 you quoted yesterday: "Conforming code must be structured so
that its results and observable side effects are the same whether or
not compilation takes place."

I'd call that inconsistent in spirit, if not in letter, with 1.5.2.1
except that it's not clear just what it means.  That sentence is
followed (in section 3.2.2.3) by a list of specific "semantic
constraints" and the somewhat unclear claim that "conforming programs
obeying these constraints have the same behavior whether evaluated
or compiled."  This sounds as if conforming programs don't have to
obey these constraints, but _if they do_, then they'll have the
same behavior.

In any case, some other constraints about compilation must be involved
at some point, because merely obeying these constraints isn't enough
to get the same behavior.  (Eg, my example from yesterday.)

I wouldn't care about this so much if there was some other class
of "programs with semantics" more inclusive than the class of
conforming programs, but "conforming" already seems to be fairly
inclusive since it allows different results in other cases.  
Having a still more inclusive class just for the compilation issue
seems silly.  (Compare with the C standard's conforming and 
strictly conforming.  CL's conforming is similar to C's comforming
except for the compilation issue where it's more like strictly
conforming.)

> >seriously think that the behavior of the following program is or
> >should be completely undefined, ie that it might be anything at all?
> >
> >(defun g ()
> >  (flet ((f (x) x))
> >    (typep #'f 'compiled-function)))
> 
> Lisp's introspective facilities make it difficult to use general rules
> about interpreter/compiler equivalence (we considered getting rid of the
> COMPILED-FUNCTION type, though).  I agree that it's not totally undefined,
> but it isn't well-defined whether it returns T or NIL.  Once it's been
> compiled it's guaranteed to return T, but before then it could return
> either.  On some systems it will return T all the time, even though these
> systems use a traditional interpreter; to simplify FUNCALL and APPLY, they
> implement interpreted functions as a closure of a compiled interpreter
> function over the lambda expression.

I agree with all of that.

However, I would like to be sure that the dpANS more or less says
_that_ rather than saying the code is meaningless.

Here are some other cases to worry about:

1. I have an EQ hash table.  Some of the keys appear as quoted
   lists in my program.  The compiler might coalesce some of those lists.
   I call HASH-TABLE-COUNT on the table and return the result.
   (Similar effects can be obtained via LOAD-TIME-VALUE.  Or I might
   use, say, MAPHASH instead of HASH-TABLE-COUNT.)

2. I want to make sure certain functions are compiled, so if
   (TYPEP f 'COMPILED-FUNCTION) is false of one of them I compile
   it.  (I'm willing to live with implementations that give functions
   type COMPILED-FUNCTION even though they're really interpreter.)
   So far this is conforming.  Now I add an observable side effect
   by asking the user, the first time I want to compile one of these
   functions, "Do you want me to compile these functions if they're
   not already compiled?"  This makes sense in, say, KCL where
   COMPILE is slow.  Note that it may be that the functions will
   already be compiled if my program has been compiled because
   they're created by something like

      (defun make-one-of-those-functions (data)
        #'(lambda (arg) ...))

3. I define a function and a compiler macro with the same name and the
   same semantics except that the function counts how many times it's
   called and stores the count on the plist of the name.  (In general,
   compiler macros present issues similar to those of inlining but
   w/o (it seems) so many explicit consistency requirements in the
   dpANS.)
   
4. F counts how many times it's called.  I call F inside LOAD-TIME-VALUE.

5. I have some macros I don't need at run time except when interpreted
   and so I write something like this:

     (eval-when (compile eval)
       (defmacro M ...))

(Not a complete list.)

My point is simply that I ought to be able to do such things as
call HASH-TABLE-COUNT without putting my program completely beyond
the pale as far as defined semantics is concerned.  It looks to me
like the dpANS already allows this sort of thing (eg, calls to
RANDOM) _except_ when the difference is one involving compilation.

(Note too that there are almost bound to be some differences in
observable side effects depending on whether the compiled or not
compiled version of a file is laoded.  Eg, some symbols such as
the names of local variables may be "compiled away".)

-- jd
Newsgroups: comp.lang.clos