The mystery of EXPLAIN

Richard M Kreuter <[email protected]> Wed, 14 Feb 2007 19:21:21 -0500
Newsgroups gmane.lisp.cclan.general
Message-ID <[email protected]>
Hello,

asdf's EXPLAIN is kinda mysterious.  The manual documents it as part
of the operation protocol, but doesn't say how or why to extend it,
and the example "dry run" invocation in the manual is wrong.
Eventually, maybe, I'll learn to stop reading the manual; however, the
implementation of EXPLAIN in asdf.lisp doesn't clarify much either.
I've got a guess as to what was intended; can anybody review my
sleuthing?

Here are the clues:

(a) Pitman's paper, "The Description of Large Systems", calls for a
    couple of EXPLAIN-like functions.  I guess that's the inspiration.

(b) Pitman's DEFSYSTEM proposal to X3J13 called for :SIMULATE keywords
    to the (functional interface to the) compile and load operations;
    if the keyword was supplied, the operations were to do
    approximately what the paper's EXPLAIN functions did.

(c) The only defined method for EXPLAIN doesn't do much.  In
    particular, it doesn't walk the system's components.

(d) Further, the default method prints to *VERBOSE-OUT*, which, as
    long as I've been paying attention, has only ever been a stream
    during the dynamic extent of OPERATE.  When you call EXPLAIN from
    the repl, nothing gets printed, as *VERBOSE-OUT* is nil.

(e) Unlike OPERATE, which accepts designators for operation classes
    and systems, EXPLAIN only accepts operation and system instances.

(d) and (e) together seem to suggest that EXPLAIN is only meant to be
called during a call to OPERATE, when *VERBOSE-OUT* is a stream, and
when asdf is dealing with instances, rather than names.  (c) suggests
that some other part of asdf is supposed to be responsible for
traversing the system's components, like how OPERATE does.  Maybe
there's supposed to be a (b)-like argument to OPERATE that causes
EXPLAIN be called, rather than PERFORM?

So that's my guess: OPERATE was supposed to take a flag, which, if
present, made it call EXPLAIN instead of PERFORM.  It's easy to
augment OPERATE this way, so that you can get a formatted printout of
the traversal by calling (operate 'load-op 'system :explain t).
(Patches below, but see the next paragraph.)

However, this raises a policy question: under what circumstances can
keyword arguments be added to OPERATE?  All the keyword arguments get
passed along as initargs MAKE-INSTANCE, but that means that any new
keyword to OPERATE might conflict with some third-party operation
class's initargs.  It would be possible to use symbols in the ASDF
package for new keywords, I suppose, but I didn't do that below.

Thanks,
RmK


--- asdf.lisp	6 Feb 2007 17:15:58 -0000	1.105
+++ asdf.lisp	14 Feb 2007 23:24:23 -0000
@@ -885,7 +889,7 @@
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;; invoking operations
 
-(defun operate (operation-class system &rest args &key (verbose t) version 
+(defun operate (operation-class system &rest args &key (verbose t) version explain
                                 &allow-other-keys)
   (let* ((op (apply #'make-instance operation-class
 		    :original-initargs args
@@ -899,7 +903,9 @@
 	(loop for (op . component) in steps do
 	     (loop
 		(restart-case 
-		    (progn (perform op component)
+		    (progn (if explain
+			       (explain op component)
+			       (perform op component))
 			   (return))
 		  (retry ()
 		    :report


--- asdf.texinfo	21 Jan 2007 14:09:52 -0000	1.6
+++ asdf.texinfo	15 Feb 2007 00:09:01 -0000
@@ -472,9 +472,10 @@
 @end itemize
 
 Operations can be invoked directly, or examined to see what their
-effects would be without performing them.  @emph{FIXME: document how!}  There
-are a bunch of methods specialised on operation and component type
-that actually do the grunt work.
+effects would be without performing them, by passing the argument
+@code{:explain} to @code{operate}. There are a bunch of methods
+specialised on operation and component type that actually do the grunt
+work.
 
 The operation object contains whatever state is relevant for this
 purpose (perhaps a list of visited nodes, for example) but primarily
@@ -1073,19 +1074,6 @@
 
 lift unix-dso stuff from db-sockets
 
-** Diagnostics
-
-A ``dry run'' of an operation can be made with the following form:
-
-@lisp
-(traverse (make-instance '<operation-name>)
-          (find-system <system-name>)
-          'explain)
-@end lisp
-
-This uses unexported symbols.  What would be a nice interface for this
-functionality?
-
 @node  missing bits in implementation, Inspiration, TODO list, Top
 @comment  node-name,  next,  previous,  up
 @chapter missing bits in implementation


-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV