jaffer@gerber.ai.mit.edu (Aubrey Jaffer) (03/06/91)
`Load' as defined in Revised^3.99 Report on the Algorithmic Language Scheme [Draft August 31, 1989] has several problems owing to its dynamic nature: 1) `load' opens a back door to eval: (define global-eval-return #f) (define (eval frob) (call-with-output-file "tmp1" (lambda (file) (write (list 'set! 'global-eval-return frob) file))) (load "tmp1") global-eval-return) 2) `load' does not specifiy the lexical environment in which the forms are evaluated. 3) A scheme program that includes a `load' in it will cause the run time system to need to include either an interpreter or compiler. Making `load' a derived expression rather than a procedure solves all these problems. I will call it `include' in order to avoid name confusion. The Report entry would be something like: ------------------------------------------------------------------------ (include filename) essential syntax Filename should be a string naming an existing file containing Scheme source code <expression1> <expression2> .... The <expression>s are evaluated as though contained in a surrounding begin form (begin <expression1> <expression2> ...) in the lexical environment. Some implementations may require that if the file specified by filename contains definitions and the include loading it is inside a <body> then the the definitions must be at the beginning of the file and the include must be before any expressions in the <body> which are not includes or definitions. If the contents of the file specified by <filename> change during execution of the program then the actions of include are not specified. Include does not affect the values returned by current-input-port and current-output-port. Include returns the value of the last <expression> in the file. ------------------------------------------------------------------------ In the Derived Expression Types section would be the rewrite rule: (include <filename>) = (begin <file-expression1> <file-expression2> ...) A macro for include would be: (define-macro include (lambda (filename) (cons 'begin (call-with-input-file filename (lambda (file) (let next ((r (read file))) (if (eof-object? r) '() (cons r (next (read file)))))))))) The above problems are solved: 1) Expressions cannot be evaluated (included) which are not known at compile time. 2) The lexical environment of the expressions in the file is the lexical environment of the (include <filename>) form. 3) In a compiled only system all the files included are required to be present at compile time. A runtime eval is not needed. This definition of include will satisfy most existing use of load. In addition, it allows definitions to be loaded into a lexical environment without affecting the global environment: (define (add-with-modular-arithmetic . args) (include "modular-arithmetic-functions.scm") (apply + args)) Incompatability issues: 1) Include specifies a return value. Load does not. 2) Include does not make sense on non-source files. Load allows implementation dependent behavior on non-source files. For an interpreted system, an interesting extension is to have (include #f) call the read-eval-print loop in the current lexical environment. If the interpreter does not care about mixing defines and expressions this would implement separate name spaces which several people have asked for.
Alan@lcs.mit.EDU (Alan Bawden) (03/07/91)
Date: 5 Mar 91 16:03:02 GMT From: Aubrey Jaffer <jaffer@gerber.ai.mit.edu> ... Making `load' a derived expression rather than a procedure solves all these problems. I will call it `include' in order to avoid name confusion. The Report entry would be something like: ------------------------------------------------------------------------ (include filename) essential syntax Filename should be a string naming an existing file containing Scheme source code <expression1> <expression2> .... The <expression>s are evaluated as though contained in a surrounding begin form (begin <expression1> <expression2> ...) in the lexical environment. ... I think we talked about this idea a bit at Snowbird. I believe the major objection was that <filename> isn't an arbitrary expression. That is, people wanted to be able to -compute- which file to load. (Please note: I'm not endorsing this position, I'm just trying to remember the history.) There may also have been concerns that a restriction like: If the contents of the file specified by <filename> change during execution of the program then the actions of include are not specified. ... (which does seem necessary in order to make sense of the idea) may raise some issues about the differences between read-time, macroexpand-time, syntax-time, compile-time, load-time and run-time that Scheme has so far avoided addressing. (Again this is not my opinion, just my memory of the history.)