Path: utzoo!utgpu!news-server.csri.toronto.edu!clyde.concordia.ca!mcgill-vision!snorkelwacker!usc!jarthur!elroy.jpl.nasa.gov!jato!granite!brian From: brian@granite.jpl.nasa.gov (Brian of ASTD-CP) Newsgroups: comp.lang.scheme Subject: On the standard behavior of "load" Summary: load should return #t and #f Message-ID: <3601@jato.Jpl.Nasa.Gov> Date: 7 May 90 20:04:19 GMT Sender: news@jato.Jpl.Nasa.Gov Reply-To: brian@granite.Jpl.Nasa.Gov (Brian of ASTD-CP) Organization: Jet Propulsion Laboratory, Pasadena, CA Lines: 95 I would like to start a discussion concer- ning the Scheme essential procedure "load". The Scheme definition, R3.99RRS, states that the re- turn value of "load" is unspecified. However, I think that "load" should have a specified return value, and the next few paragraphs explain why I think so. With many implementations of Scheme, load returns #f when the file passed to it is not found, and #t otherwise. I think this ought to be the standard behavior of load. In some newer, more "Graphical User Interface"-oriented implementations of Scheme, load presents an interactive dialog, asking the user to pick a file from a list when the given file is not found. With this behavior, load is not permitted to return #f and load cannot be used in unattended programs when it might return #f. However, there is a very good reason why one might want load to tell a program that it can't find a file. Imagine that a collection of software is divided into modules and clients. The modules are reusable abstract data types, procedures, libraries, etc. The clients are programs built up from the modules. It is highly advantageous to maintain the modules separately from the clients. In particular, clients should not require knowledge of the directories modules reside in. Clients should simply refer to modules by name, as in (load-module "methods.sch") (load-module "queues.sch") (load-module "binary-search.sch") If clients use only load, then they must have hard-coded directory names, as in: (load "MyDisk:Scheme Code:Modules:OOP:methods.sch") (load "MyDisk:Scheme Code:Modules:OOP:classes:queues.sch") (load "MyDisk:Scheme Code:Modules:Procedures:binary-search.sch") and so on. The big maintenance problem occurs when a module is moved. Using load-module, no clients need to be changed. Using load, however, all clients of a module must be manually tracked down and changed. The implementation of load-module is simple. It searches a canonical list of module directories, using the return value of load to decide whether to continue or terminate the search. (define (load-module filename) (let iter ((canon-dir-list (list "MyDisk:Scheme Code:Modules:" "MyDisk:Scheme Code:Modules:OOP:" "MyDisk:Scheme Code:Modules:OOP:classes:" "MyDisk:Scheme Code:Modules:Procedures:" ))) (cond ( (null? canon-dir-list) #f ) ( (load (string-append (car canon-dir-list) file)) ) ( else (iter (cdr canon-dir-list)) )))) (my real load-module is a little different because it avoids loading a module more than once, but the version above illustrates the use of load in load-module.) With load-module, if a module directory is changed, only the canonical directory list, which is in one place in an initialization file, need be changed. All static data concerning module locations is hidden in this single list, rather than being distributed in multiple copies among the clients, which is clearly a much inferior organization. It should be clear that load-module relies on load's returning #f when a file is not found in a directory. The ostensibly more user friendly dialog behavior of load actually forces a developer of Scheme code to violate separation of module and client and to pollute client code with extrinsic information that creates a maintenance headache. Comments? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Brian Beckman . . . . . . . . . . brian@granite.jpl.nasa.gov. . . . . . meta-disclaimer: every statement in this message is false . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .