CoCreate Modeling: Using symbol-function
In the
termination event example, we used an event
to perform last rites while the application shuts down. Alternatively,
it's possible to overload the Lisp
exit
function using the Common Lisp
symbol-function accessor.
;; -*-Lisp-*-
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Description: Hooks into exit to perform last rites
;; Author: Claus Brod
;; Created: 1/14/2005
;; Language: Lisp
;;
;; (C) Copyright 2005 Claus Brod, all rights reserved
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
(in-package :clausbrod.de)
(use-package :oli)
(let ((original-exit (symbol-function 'exit)))
(defun my-exit(&rest args)
(when (equal :yes (oli:sd-display-question "Really, really quit?"))
(if args
(apply original-exit args)
(funcall original-exit)
)
)
)
(setf (symbol-function 'exit) (symbol-function 'my-exit))
)
Watch out: Your replacement for
exit
must fit the original function
signature. Check your code carefully; when experimenting with this
stuff, it's all too easy to end up with infinite recursions, creative
crashes, and frustration.
--
ClausBrod - 14 Jan 2005
Claus, can you explain your rationale for doing the above inside a "let" form? Thanks,
--
TomBower - 11 Jan 2006
let
establishes a lexical binding for
original-exit
; the variable is only
valid within the scope of the
let
statement. This construct turns
original-exit
into something that
resembles a global variable, but without the
drawbacks which are usually associated with global variables, such as
namespace pollution or access to the variable from places which shouldn't
know about it - with my approach,
original-exit
is only visible for the
code which really needs to see it.
To a C programmer, the closest analogy is a module-static variable:
static function_pointer original_exit = symbol_function("exit");
bool my_exit(...)
{
...
}
However, the C analogon is visible throughout the file where it is defined,
whereas the Lisp variable
original-exit
(or rather its binding) is visible
only to whatever is in the scope of
let
.
The alternative would be to use a special variable at top-level, i.e. something like
(defvar *original-exit* (symbol-function 'exit))
defvar
makes
*original-exit*
a
special variable defined at top-level.
I prefer the
let
approach and try to avoid special
variables wherever I can. "Special variable" is in fact a technical
term in Lisp and denotes a type of variables with
dynamic binding, as opposed
to
lexical binding. This is confusing language lawyer stuff, but it is
of practical relevance, and I hope I'll get around to
discussing special variables and lexical binding soon. If you can't wait and
need to know more now, read the chapter on "Variables" in Peter Seidel's wonderful
Practical Common Lisp.
HTH.
--
ClausBrod - 11 Jan 2006
I elaborated on this now in my software blog - see
"I'm so special".
--
ClausBrod - 12 Feb 2006