Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

How to programmatically exit?

431 views
Skip to first unread message

Russell Wallace

unread,
Oct 25, 2008, 12:13:31 PM10/25/08
to
From within a portable Lisp program, how do you exit cleanly to the
operating system (as opposed to the debugger), i.e. the equivalent of
exit(0) in C? I can't find anything in the hyperspec or Google, but
maybe I'm overlooking something obvious.

Lars Rune Nøstdal

unread,
Oct 25, 2008, 1:06:05 PM10/25/08
to

CL-USER> (cffi:foreign-funcall "exit" :int 0)
...
Process inferior-lisp exited abnormally with code 0

--
Lars Rune Nøstdal || AJAX/Comet GUI type stuff for Common Lisp
http://nostdal.org/ || http://groups.google.com/group/symbolicweb

Waldek Hebisch

unread,
Oct 25, 2008, 2:11:06 PM10/25/08
to

Such functionality is missing from ANSI CL, so any solution will
be more or less unportable. The following is a reasonable
approximation for free Lisp implementations, basically you
need special case for each implementation (if you know correct
code for other implementations I would appreciate such info).
Note: the code is intended to be used in a portablility
package, so called functionos use qualified names.

;;; How to exit Lisp process

#+:gcl
(defun quit() (lisp::quit))

#+:sbcl
(defun quit()
(sb-ext::quit))

#+:clisp
(defun quit() (ext::quit))

#+:openmcl
(defun quit() (ccl::quit))

#+:ecl
(defun quit ()
(SI:quit))

#+:poplog
(defun quit() (poplog::bye))

--
Waldek Hebisch
heb...@math.uni.wroc.pl

Tamas K Papp

unread,
Oct 25, 2008, 2:42:30 PM10/25/08
to

Presumably, you are starting that program somehow, which is already
implementation dependent. Do something like

sbcl --eval '(progn (load-what-I-need) (run-my-wonderful-program) (quit))'

for each implementation that your program is supposed to work with.

You can make run-my-wonderful-program portable and independent of the
implementation. When that function terminates, the program will quit.

Inside your program, define a condition that signals intention to quit.
Have run-my-wonderful-program handle it by returning.

HTH,

Tamas

Lars Rune Nøstdal

unread,
Oct 25, 2008, 3:19:17 PM10/25/08
to
On Sat, 2008-10-25 at 19:06 +0200, Lars Rune Nøstdal wrote:
> On Sat, 2008-10-25 at 09:13 -0700, Russell Wallace wrote:
> > From within a portable Lisp program, how do you exit cleanly to the
> > operating system (as opposed to the debugger), i.e. the equivalent of
> > exit(0) in C? I can't find anything in the hyperspec or Google, but
> > maybe I'm overlooking something obvious.
>
> CL-USER> (cffi:foreign-funcall "exit" :int 0)
> ...
> Process inferior-lisp exited abnormally with code 0
>

Just came over this:
http://www.cliki.net/cl-launch

..search that page for cl-launch:quit .. might make sense; you'll have a
portable way to start stuff also then.

Rob Warnock

unread,
Oct 25, 2008, 9:09:13 PM10/25/08
to
Waldek Hebisch <heb...@math.uni.wroc.pl> wrote:
+---------------
| Russell Wallace <russell...@gmail.com> wrote:
| > From within a portable Lisp program, how do you exit cleanly...
| > exit(0) in C? I can't find anything in the hyperspec or Google...

| > maybe I'm overlooking something obvious.
|
| Such functionality is missing from ANSI CL, so any solution will
| be more or less unportable. The following is a reasonable
| approximation for free Lisp implementations...
...

| ;;; How to exit Lisp process
| #+:gcl
| (defun quit() (lisp::quit))
|
| #+:sbcl
| (defun quit()
| (sb-ext::quit))
+---------------

And so on...

A style that's less visually confusing (IMHO) puts all of the
feature tests[1] inside a single copy of the function in question,
documenting the common API in a single place. The following is
a merge of the set from <http://www.cliki.net/CLOCC-PORT>, the
set from Maxima, and yours:

(defun quit (&optional code)
;; This group from "clocc-port/ext.lisp"
#+allegro (excl:exit code)
#+clisp (#+lisp=cl ext:quit #-lisp=cl lisp:quit code)
#+cmu (ext:quit code)
#+cormanlisp (win32:exitprocess code)
#+gcl (lisp:bye code) ; XXX Or is it LISP::QUIT?
#+lispworks (lw:quit :status code)
#+lucid (lcl:quit code)
#+sbcl (sb-ext:quit
:unix-code (typecase code (number code) (null 0) (t 1)))
;; This group from Maxima
#+kcl (lisp::bye) ; XXX Does this take an arg?
#+scl (ext:quit code) ; XXX Pretty sure this *does*.
#+(or openmcl mcl) (ccl::quit)
#+abcl (cl-user::quit)
#+ecl (si:quit)
;; This group from <heb...@math.uni.wroc.pl>
#+poplog (poplog::bye) ; XXX Does this take an arg?
#-(or allegro clisp cmu cormanlisp gcl lispworks lucid sbcl
kcl scl openmcl mcl abcl ecl)
(error 'not-implemented :proc (list 'quit code)))


-Rob

p.s. Note that you never need an explicit keyword package marker on
a symbol in a feature test, e.g. #+:FOO, since feature expressions
are read *in* the KEYWORD package, see CLHS "2.4.8.17 Sharpsign Plus",
"2.4.8.18 Sharpsign Minus", & "24.1.2.1 Feature Expressions".

-----
Rob Warnock <rp...@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607


Thomas A. Russ

unread,
Oct 27, 2008, 2:25:49 PM10/27/08
to
Waldek Hebisch <heb...@math.uni.wroc.pl> writes:

> Russell Wallace <russell...@gmail.com> wrote:
> > From within a portable Lisp program, how do you exit cleanly to the
> > operating system (as opposed to the debugger), i.e. the equivalent of
> > exit(0) in C? I can't find anything in the hyperspec or Google, but
> > maybe I'm overlooking something obvious.
>
> Such functionality is missing from ANSI CL, so any solution will
> be more or less unportable. The following is a reasonable
> approximation for free Lisp implementations, basically you
> need special case for each implementation (if you know correct
> code for other implementations I would appreciate such info).
> Note: the code is intended to be used in a portablility
> package, so called functionos use qualified names.
>
> ;;; How to exit Lisp process

Given the prevalence of the use of QUIT as the name of such a function,
I have sometimes resorted to the following outrageous hack. But it does
have a fair bit of portability, since it relies the implementations
making the quit symbol available from the CL-USER package.

Simple form:

(defun my-quit () (funcall (find-symbol "QUIT" "COMMON-LISP-USER")))

More robust:
(defun my-quit ()
(let ((quit-symbol (find-symbol "QUIT" "COMMON-LISP-USER"))
(exit-symbol (find-symbol "EXIT" "COMMON-LISP-USER")))
(when (and quit-symbol (fboundp quit-symbol))
(funcall quit-symbol))
(when (and exit-symbol (fboundp exit-symbol))
(funcall exit-symbol))
(warn "Don't know how to quit!")))


> #+:poplog
> (defun quit() (poplog::bye))

OK, it would miss this one, though...

--
Thomas A. Russ, USC/Information Sciences Institute

Russell Wallace

unread,
Oct 27, 2008, 7:05:59 PM10/27/08
to
Thanks to everyone who replied! The solution I ended up going with is
(catch nil ...) at the top level, then (throw nil nil) to exit from a
low-level function.

Willem Broekema

unread,
Oct 27, 2008, 8:48:25 PM10/27/08
to
On Oct 26, 2:09 am, r...@rpw3.org (Rob Warnock) wrote:
> (defun quit (&optional code)
> ;; This group from "clocc-port/ext.lisp"
> #+allegro (excl:exit code)
> #+clisp (#+lisp=cl ext:quit #-lisp=cl lisp:quit code)
> ...

>     #-(or allegro clisp cmu cormanlisp gcl lispworks lucid sbcl
>           kcl scl openmcl mcl abcl ecl)
>     (error 'not-implemented :proc (list 'quit code)))

You could even skip the #-(...) in this case. :)

- Willem

Rob Warnock

unread,
Oct 28, 2008, 6:47:57 AM10/28/08
to
Willem Broekema <meta...@gmail.com> wrote:
+---------------
+---------------

Yes, that's true. But exiting the entire program is a very special
case and I didn't want to encourage sloppiness in the general case
where you *do* want to return a value, e.g., this function from the
"archive_0.7.0" package:

;;; stat field accessors
(defun stat-mode (stat)
#+sbcl (sb-posix::stat-mode stat)
#+lispworks (file-stat-mode stat)
#+clisp (posix:convert-mode (posix:file-stat-mode state))
#+cmucl (mode stat)
#-(or sbcl lispworks clisp cmucl) (error "Not implemented"))

So it's probably best to always include the #-(OR ...) list,
just to avoid mistakes by accident.

Although, now that you mention it, there *is* one other special case
that I can think of where the #-(OR ...) is unnecessary and, in fact,
unwanted, and that's where you're going to return a default value if
the implementation-specific value is NIL, e.g.:

;;; This version morphed very slightly from
;;; <http://cl-cookbook.sourceforge.net/os.html>
(defun getenv (name &optional default)
(or
#+cmu (cdr (assoc name ext:*environment-list* :test #'string=))
#+allegro (sys:getenv name)
#+clisp (ext:getenv name)
#+ecl (si:getenv name)
#+sbcl (sb-unix::posix-getenv name)
#+lispworks (lispworks:environment-variable name)
default))


-Rob

Madhu

unread,
Oct 31, 2008, 2:39:49 AM10/31/08
to

* (Rob Warnock) <RaadnbmwuIJAcJvU...@speakeasy.net> :
Wrote on Tue, 28 Oct 2008 05:47:57 -0500:

| Willem Broekema <meta...@gmail.com> wrote:
| +---------------
| | rp...@rpw3.org (Rob Warnock) wrote:
| | > (defun quit (&optional code)
| | > ;; This group from "clocc-port/ext.lisp"
| | > #+allegro (excl:exit code)
| | > #+clisp (#+lisp=cl ext:quit #-lisp=cl lisp:quit code)
| | > ...
| | > #-(or allegro clisp cmu cormanlisp gcl lispworks lucid sbcl
| | > kcl scl openmcl mcl abcl ecl)
| | > (error 'not-implemented :proc (list 'quit code)))
| |
| | You could even skip the #-(...) in this case. :)
| +---------------
|
| Yes, that's true. But exiting the entire program is a very special
| case and I didn't want to encourage sloppiness in the general case
| where you *do* want to return a value, e.g., this function from the
| "archive_0.7.0" package:
|
| ;;; stat field accessors
| (defun stat-mode (stat)
| #+sbcl (sb-posix::stat-mode stat)
| #+lispworks (file-stat-mode stat)
| #+clisp (posix:convert-mode (posix:file-stat-mode state))
| #+cmucl (mode stat)
| #-(or sbcl lispworks clisp cmucl) (error "Not implemented"))


I don't like the double listing of features in the #-( ... ) forms. To
avoid them I'd suggest the following Pattern that I use myself:

(defun stat-mode (stat)
(or


#+sbcl (sb-posix::stat-mode stat)
#+lispworks (file-stat-mode stat)
#+clisp (posix:convert-mode (posix:file-stat-mode state))
#+cmucl (mode stat)

(error "Not implemented")))

Any drawbacks? (I don't think so...)

--
Madhu

William James

unread,
Oct 31, 2008, 2:43:49 PM10/31/08
to

Ruby:

exit

Raffael Cavallaro

unread,
Oct 31, 2008, 6:01:12 PM10/31/08
to
On 2008-10-31 14:43:49 -0400, William James <w_a_...@yahoo.com> said:

> Ruby:
>
> exit

Naturally, just as defined in the Ruby ANSI standard, I mean ISO standard...

Oh, wait...

Thomas F. Burdick

unread,
Nov 1, 2008, 8:08:43 AM11/1/08
to
On Oct 28, 12:05 am, Russell Wallace <russell.wall...@gmail.com>
wrote:

> Thanks to everyone who replied! The solution I ended up going with is
> (catch nil ...) at the top level, then (throw nil nil) to exit from a
> low-level function.

Just a word of caution: do you really want to have NIL mean end-of-the-
world? If you ever end out throwing to nil on accident, you'll end out
not in the debugger but quietly exiting. It's probably not a big deal
(although the gun is pointed at your foot, the safety is on and the
chamber's empty) but I always call catch tags like yours above
something more like :goodbye-world or %exit or something.

Russell Wallace

unread,
Nov 1, 2008, 12:41:46 PM11/1/08
to
On Nov 1, 12:08 pm, "Thomas F. Burdick" <tburd...@gmail.com> wrote:
> Just a word of caution: do you really want to have NIL mean end-of-the-
> world? If you ever end out throwing to nil on accident, you'll end out
> not in the debugger but quietly exiting. It's probably not a big deal
> (although the gun is pointed at your foot, the safety is on and the
> chamber's empty) but I always call catch tags like yours above
> something more like :goodbye-world or %exit or something.

What you're saying makes sense; I started off using nil to mean
basically "error parsing data file, so exit"; but then I added support
for processing several files in a batch, so I actually changed the
location of the catch, to mean "okay, ignore that file, but proceed to
the next one"; so I'll probably keep using nil to mean "done here, let
top-level decide what to do next".

This of course is an advantage of throw over explicit exit -- you can
change your mind about how to handle the situation, without having to
modify the low-level code.

Thomas F. Burdick

unread,
Nov 1, 2008, 3:49:52 PM11/1/08
to

Okay, that makes a lot of sense.

One last stylistic nit to pick: do you know about restarts, and
specifically ABORT? You've notice in your debugger that you often have
the option of invoking a restart called ABORT? There's a standard
function cl:abort that invokes it; there's also CONTINUE as a standard
name for a restart. If you have some concept of "the current
operation" in your application, it can be convenient to have ABORT,
well, abort it and return to the top-level loop, whatever that loop
may be. In Ltk, for example, we create an abort restart that aborts
handling the latest event (user input, button press, timeout, etc) and
returns to the main event loop. It interacts nicely with standard
debuggers.

The idiom is like this:

(loop while (keep-going-p)
do (restart-case
(do-one-iteration)
(abort ()
:report "Abort processing this file"
nil)))

Sometimes catch is better, sometimes restarts are more convenient,
just food for thought.

(OMG is that a pattern?! No, wait, it's an idiom. I guess I formatted
it differently?)

Russell Wallace

unread,
Nov 1, 2008, 4:35:23 PM11/1/08
to
On Nov 1, 7:49 pm, "Thomas F. Burdick" <tburd...@gmail.com> wrote:
> One last stylistic nit to pick: do you know about restarts, and
> specifically ABORT? You've notice in your debugger that you often have
> the option of invoking a restart called ABORT? There's a standard
> function cl:abort that invokes it; there's also CONTINUE as a standard
> name for a restart. If you have some concept of "the current
> operation" in your application, it can be convenient to have ABORT,
> well, abort it and return to the top-level loop, whatever that loop
> may be. In Ltk, for example, we create an abort restart that aborts
> handling the latest event (user input, button press, timeout, etc) and
> returns to the main event loop. It interacts nicely with standard
> debuggers.

Thanks! I hadn't thought of that, but I'll keep it in mind.

0 new messages