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

Re: Issue: REQUIRE-PATHNAME-DEFAULTS (Version 3)



> In summary I claim that a loading REQUIRE has two unacceptable traits:
>  - People will use and depend on the loading feature.
>  - This will make REQUIRE an obstacle to portable code.

That would seem to me to be an argument for making file loading a
required part of the functionality.  It is trivial to define a way to
associate a module name with a list of file names to be loaded; there
really isn't any reason why every implementation couldn't have a way to
do that.  The hard part about defining a file-loading utility is to have
it compile files that need to be compiled and to do the compiling and
loading in the right order, but it is quite sufficient for REQUIRE to
just load previously compiled files.  As an existence proof I offer the
following portable implementation of REQUIRE.  The call to DEFINE-MODULE
is necessarily implementation dependent because of pathname syntax and
directory usage, but re-doing it or its equivalent for each
implementation ported to would not be a big problem.


(DEFVAR *MODULES* NIL "List of modules marked present with PROVIDE.")
 
(DEFUN PROVIDE (MODULE)
  "Mark MODULE as being already loaded."
  (PUSHNEW (STRING MODULE) *MODULES* :TEST #'STRING=)
  (VALUES))

(DEFVAR *MODULE-HASH-TABLE* (MAKE-HASH-TABLE :TEST #'EQUAL))

(DEFUN DEFINE-MODULE (NAME &REST FILE-NAMES)
  "Specify which files REQUIRE should load for module NAME."
  (SETF (GETHASH (STRING NAME) *MODULE-HASH-TABLE*)
	(MAPCAR #'MERGE-PATHNAMES FILE-NAMES))
  NAME)

(DEFUN REQUIRE (MODULE)
  "Ensure that MODULE is loaded."
  (LET ((NAME (STRING MODULE)))
    (LOOP
      (IF (MEMBER NAME *MODULES* :TEST #'STRING=)
	  (RETURN)
	(LET ((FILES (GETHASH NAME *MODULE-HASH-TABLE* NIL)))
	  (IF (NULL FILES)
	      (CERROR "Re-try the REQUIRE call after manually loading the module."
		      "Required module ~S is neither loaded nor defined." NAME)
	    (LET ((MODULES *MODULES*))
	      (UNWIND-PROTECT
		  (PROGN (MAPC #'LOAD FILES)
			 (PROVIDE NAME)
			 (SETQ MODULES *MODULES*))
		(SETQ *MODULES* MODULES))
	      (RETURN)))))))
  (VALUES))