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


I'm sorry, but I just will not support the idea of a single function QUIT
as is currently being discussed. If the problem were re-cast, it might be
soluble, but I believe the problem as I've seen it stated thus far is just
plain insoluble.

I base my criticisms on experience that I have from create a portable 
QUIT function for use in Macsyma internals. I created such a function
using various non-portable primitives provided by particular dialects
I was studying. As with the GC problem, I found that the idea seemed
superficially plausible but just didn't work out in practice. Here are
some of my observations and conclusions ...

 1. Where is control transfered?

    Of the implementations which primitively offer some variant of QUIT, 
    all that I know of are on partitioned address space machines  which
    have a basically tree-structured process system that offers a 
    distinguished superior (usually an exec) to which it is obvious that
    control should be transfered upon call to QUIT.
    Shared address space machines (ie, Lisp Machines) have the problem 
    that there is no tree of processes. All occupy an equal status and 
    there is no obvious process to which control should be returned.

 2. What is a process?
    On partitioned address space machines, each process typically 
    comes with its own "global" state. Killing a process means killing its
    "global" state. On shared address machines, killing the process will
    generally kill only its dynamic state, not its global state (which
    is generally intertwined with the global state of other processes).
    To kill its global state means killing the global state of sibling
    activities, which may be highly undesirable.

 3. Can the process be resumed?

    Even among partitioned address space machines, there is disagreement
    about whether exiting (to the exec) means that you can re-enter later.
 4. What does it mean for a process to be resumed?

    Presumably resuming leaves the global state intact. Does it restart
    the process or does the call to QUIT just return NIL?

 5. If a process is killed permanently, are the associated UNWIND-PROTECT
    cleanup forms guaranteed to run first?

Obviously, some of these issues cannot be answered by the Common-Lisp
committee.  They are architectural issues beyond the scope of the
language. If we standardize on any meaning for QUIT, however, it must be
guided by an understanding that people do not use linguistic primitives
in the absence of intent, and that we should not provide primitives
which do not allow the programmer to clearly specify some meaningful
intent.  In light of the questions I've raised above, I hope it's clear
that definitions like "Exits the Lisp system" do not make any intent

Here are some real-life scenarios that I see...

 1. If the intent was to exit, what if there was no place to go?
    On the 3600, the Lisp Listener doubles as an exec. It is the 
    standard place to which programmers return to give commands, 
    not a place to be returned from. Having a "user interface" 
    function named QUIT which was a no-op when typed to Lisp would 
    be very confusing. Having it randomly select another activity
    would be fairly useless. I feel that people don't interactively 
    ask to exit something unless they think there is an obvious 
    place to go.

 2. If the intent is to exit temporarily and the exit turns out to 
    be permanent, this can have remarkably drastic consequences. A 
    user of Macsyma would be phenomenally irritated if I offered a
    temporary-exit function and it ended up exiting permanently
    before s/he had a chance to save the MACSYMA's state.

 3. If the intent was to exit permanently and the program was 
    allowed to proceed, the effects of continuing could be very
    strange. I've found myself resorting to things like:
	(PROGN (QUIT)  ;Try a permanent exit
	       (...))  ;If we got here, the QUIT didn't work,
		       ;so try cleaning up enough to continue
    or even:
	(LOOP (QUIT))  ;Insist on a permanent exit!

 4. If the intent was to exit "lisp" permanently, destroying global
    state, I'd argue that it could not possibly have been the intent 
    of any portable program to really kill everything on the machine
    since those other things are beyond the scope of Common Lisp and
    not something that CL programs have any obvious way to reason 

    On the 3600, you can't opt to "start over" without taking the 
    Editor, Mail Reader, Peek, Telnet Windows, etc. with it. Some
    people here at Symbolics do all their work from the same Lisp for
    several weeks at a time, building up lots of state which they
    don't want thrown away casually. There is no "starting over" that
    is not synonymous with "cold booting". In the case of server
    machines, this would mean that file connections would be broken,
    mail would stop being delivered until the (sometimes long) cold
    boot sequence had run, etc. In fact, the boot sequence may not
    begin automatically just because I halt my machine. If I was
    dialing in from home, I might have to go to work to initialize 
    the system again.

    Some non-Lispms have an in-Lisp editor even though they have
    other processes which are separable. Perhaps some of those 
    users use that editor only for editing Lisp and are content to
    have the editor and the lisp go away as a unit because they do
    other text editing in an editor that doesn't go away with Lisp,
    but that's presumably a property of the user rather than the

The real problem here is that there is no such thing as exiting in the
pure abstract. Exiting means to pass through an abstract boundary
between an abitrarily chosen inside and outside. In the CL spec, we have
remained intentionally silent on the issue of where that line is drawn
in order to accomodate both Lispm-based and conventional systems.  I
think that corollary to this silence is the fact that functions which
attempt to cross the boundary are ill-defined. Not only do some systems
draw the boundary in different places than others, but some
intentionally don't draw it at all.

I don't care whether the primitive is called QUIT, EXIT, EXIT-TO-SYSTEM,
or whatever. The names themselves are not the problem. I only care that
any names we choose have a very clear behavior and that I can reason
about at coding time, or that my programs can reason about at runtime
prior to actually invoking the primitive which actually attempts to exit.

I don't plan to seriously consider any proposal for a QUIT primitive
which does not carefully address these issues.