OneSpace 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


When asked for a TWiki account, use your own or the default TWikiGuest account.

Revision: r1.9 - 01 May 2007 - 15:14 - ClausBrod
CoCreateModeling > OsdmMacros > MacroSymbolFunction
Copyright © 1999-2024 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback