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

Re: readers & tokenizers



The T model, or something like it, seems to meet the criteria
I proposed for statelessness.  What I would prefer to see us
avoid is the monolithic global model of read tables.  T seems to
offer one nice way to do that, given your description.

   I have used read-time conditionalization in the past and have concluded
   that it is not a good idea.  If a language must have conditionalization,
   it must have run-time semantics.... 
   What I always do is encapsulate implementation dependencies by defining
   an interface, and then write multiple implementations of the same
   interface.  In my experience this leads to code that's much prettier,
   more modular, AND more portable.  Why won't this work for you?

In what I recall you guys at universities calling the "real world,"
we often don't have the luxury of writing all the code ourselves,
nor even of specifying it.  One specific case I had in mind when
I wrote my note was a medium-sized (~25,000 lines of code) LISP
software tool written in Common LISP that we have been rendering
compatible with Scheme.  (Note that I did not say "porting to Scheme"
-- it must remain fully compatible with the other LISPs in which it
executes, and given its size it is unthinkable to maintain separate
versions of the source as the software is constantly extended.)

Use of #+/#- reader conditionals have permitted us to add minimal 
annotations to this software and make it compatible with Scheme.  
Perhaps more importantly, the code *already* contains #+ and #-, because  
it is "real" code written to run under 3 brands of Common Lisp, as well as 
MacLISP and Franz, and we don't have the option of ripping all that 
stuff out (nor the budget and wo/manpower to rip all the offending 
conditionalization code out).  The harsh reality was that being able to use 
existing desirable software tools required us to support #+ and #-, because 
historically that has been viewed as the "clean" way to conditionalize 
other LISP code.  (Note that this is not the same as arguing, for
example, that the Scheme reader should support InterLisp CLisp syntax
or something along those lines.  It merely recognizes that the way code
has been written to make it portable is using #+ and #-, and if we want
to make it possible to run non-trivial non-Scheme LISP code in Scheme, 
this may be the lowest-cost highest-payoff addition to Scheme's reader 
that we could make.)

I disagree with the implication that Scheme has escaped run-time
conditionalization.  I made a comment about this many months ago
when we discussed LOAD.  If we really want to be able to view our
files as containing static code, then we cannot have a LOAD of the
sort we presently use, in my view; we need an INCLUDE instead, specifically
one that is utterly literal in its interpretation.  That is, for files as
in

	file1:	(set! *closed-var 1)
		(set! *closed-var 2)

	file2:	(let ((*closed-var '()))
		      (if (read)
			  (include "file1"))
		      *closed-var)

then "loading" or "executing" file2 would be identical to executing

		(let ((*closed-var '()))
		      (if (read)
			  (set! *closed-var 1)
			  (set! *closed-var 2))
		      *closed-var)

The use of LOAD introduces some fascinating difficulties into
the sort of static analysis of code you wish to perform; for
example consider "loading or executing" file2, with contents as per

	file1:	(set! foo (lambda () (write 'goodbye)(newline)))

	file2:	(define foo (lambda () (write 'hello)(newline)))
		(if (read)
		    (load "file1"))
		(foo)

The extension to problems with macros (especially if we can redefine
IF, for example -- which I advocate permitting, BTW), is equivalently
problematic, or more so.  The point is that we already have introduced
constructs that render static analysis difficult or meaningless, even 
where there might have been cleaner alternatives (INCLUDE instead of 
LOAD, say).  I would not find an argument that this is poor use of LOAD 
very interesting, since these (ab)uses of LOAD seem to me to be very much 
in the spirit of dynamic-scoping-of-the-execution-environment that was 
precisely the reason LOAD was defined the way it was in R3RS, at least
according to my recollection of the discussion.

I also would add that, although we did create additional primitives for
managing a sort of "features list" in ADS Scheme, there is no need to do this
if you wish to have a Scheme that supports #+scheme and yet remains
susceptible to static analysis.  If the user may not change the "features
list," then the compiler always can know that #+scheme can be ignored and
that #-scheme means "the following expression reliably will be discarded."
The same static interpretation rules can hold for other #+/#- "features."  I
see no problems for static analysis in this case.

	Regards,					asc