Declarative Languages
Lecture #9

Purpose: Catch & throw etc., symbols, and more about functions

9.1 Catch and throw

We finished last time with blocks and the special operator return-from, which together allow you to make lexical exits, i.e. to leave any body of code so long as you are still in its textual region. So, for example, anywhere within the text of a function you can leave it by invoking return-from:

(defun safe-average (numbers)
  (if numbers
      (let* ((total 0))
        (dolist (number numbers)
          (if (numberp number)
              (incf total number)
            (return-from safe-average
              (format nil "~a not a number" number))))
        (float (/ total (length numbers))))))
If you are no longer within the textual extent of a block, you cannot return-from it. The following:
(defun foo ()

(defun bar ()
  (return-from foo))

will not work because you you have to place the (return-from foo) lexically (i.e. textually) within the body of the function foo.

In contrast, the special operators catch and throw have dynamic scope and avoid the above restriction. (So why ever bother to use return-from? Answer: because return-from compiles into a simple jump instruction but catch and throw have to mess with the stack, which costs at run-time.)

Simple example to demonstrate the syntax:

As a more complex example, consider this somewhat crude top-level loop with basic error handling: 9.2 unwind-protect

With all these cute possibilities for getting out of executing vast chunks of code by invoking some exit (whether return-from or throw or aborting from an error), there is the chance that some form that simply had to be executed will be missed out. The classic example is that that once you've opened some external resource (for instance a file or database connection), you want to guarantee closing it cleanly no matter what else happens, i.e. even in the face of unexpected errors.

Lisp allows you to do this, and the special operator which handles it is called unwind-protect. Its syntax is
    (unwind-protect protected-form cleanup-1 cleanup-2 ... cleanup-n)

unwind-protect evaluates protected-form and guarantees that the cleanup-forms will be executed before unwind-protect exits, whether it terminates normally or is aborted by a control transfer of some kind (i.e. return-from, throw, error).

(defun dummy (x)
  (setf status 'running)
  (if (numberp x)
      (setf status (1+ x))
    (throw 'abort 'not-a-number)))        =>  dummy

(catch 'abort (dummy 1))                  =>  2
status                                    =>  2

(catch 'abort (dummy 'trash))             =>  not-a-number
status                                    =>  running

(catch 'abort (unwind-protect (dummy 'trash)
                (setf status 'aborted)))  =>  not-a-number
status                                    =>  aborted

Notes: 9.3 funcall

The function funcall takes a function and some arguments, and calls that function with those arguments. For example,

9.4 Closures

Another really neat feature of lisp is the ability of functions to access variables which are (lexically) bound around the function definition. We can retain the value of a variable from one function invocation to the next, and share a local variable between several functions, thus:

(let* ((counter 0))
  (defun add-one ()
    (incf counter))
  (defun query ()
  (defun reset ()
    (setf counter 0)))

(query)    =>  0
(add-one)  =>  1
(query)    =>  1
(dotimes (i 5) (add-one))  => nil
(query)    =>  6
(reset)    =>  0
(query)    =>  0

except that the above is not a very interesting example (because we could have achieved the same thing by making counter a global variable). However, note that the variable counter is shared between the three functions and that its value persists between function calls.

Now consider the following (I think this is the first example we've seen of a function which generates another function as its return value):

(defun make-thingy ()
  (let* ((thing nil))
    (lambda (&optional new)
      (let* ((old thing))
        (if new
            (setf thing new))

(setf one (make-thingy))  =>  <some function object, prints ugly>
(setf two (make-thingy))  =>  <some other function object, prints ugly>

(funcall one 'first)   =>  first
(funcall two 'second)  =>  second

(funcall one)          =>  first
(funcall two)          =>  second

Every time we call make-thingy, we bind a new variable thingy. Therefore the two functions stored in one and two work with their own private copies of this variable.

Finally, in

(defun extract (table)
  (let* ((keys nil)
         (values nil))
    (maphash (lambda (key value)
               (push key keys)
               (push value values))
    (list keys values)))
the variable values though external to the lambda form is lexically bound around it and so can be used by the lambda form to return a list of the values found in the hash-table.

The above functions (that is: add-one query reset, the functions returned by calls to make-thingy and the lambda form in extract) are examples of lexical closures. We say that these functions close over the variables counter, thing, keys and values, respectively.

Closures allow you to attach state to a function. (Maybe it's more precise to say that closures are functions with permanent state, possibly shared.) In the first example three closures share access to the same closure variable, in the second a new closure is generated each time make-thingy is called and the state is not shared, in the third case the state consists of two variables, both shared with the enclosing function.

This last case is the most common. Most (but by no means all!) closures are not seen as return values.

Without closures, lambda forms wouldn't be nearly so useful. The fact that closures exist means that you can write code like extract and never have to worry about how the lambda form is going to communicate with the function it belongs to. Still, Graham is right (page 2) when he notes that a function like

;; generate a function which adds n to its argument
(defun addn (n)
  (lambda (x)
    (+ x n)))
simply couldn't be contemplated in C.

9.5 Symbols and names

We have on our travels encountered a number of general (i.e. they can contain any lisp objects) data structures, as in the table in last week's notes:
    cons    vector    structure    hash-table
and a one specialized data structure:
We will look now at one semi-specialized structure which we've been using all along: the symbol. I say semi-specialized because one of its fields can contain what you like, and the others can't.

A symbol can be thought of as a named object. It is of type symbol, and responds positively to symbolp. Note that all keywords are symbols.

To access a symbol, type its name. To create a symbol, type its name (although see also the functions make-symbol and intern). To discover whether a symbol with a given name already exists, use the function find-symbol (which takes the name of the putative symbol as a string). To go from a symbol to its name, use the function symbol-name

(find-symbol "FOO")  =>  nil     ; since this symbol does not exist yet
'foo  =>  foo                    ; simply typing the symbol creates it
(find-symbol "FOO")  =>  foo     ; and so the symbol is now present
(symbol-name 'foo)   =>  "FOO"
(symbol-name :foo)   =>  "FOO"   ; symbols foo and :foo have the same name!
(type-of 'foo)       =>  symbol
(mapcar 'symbolp '(foo t nil :wibble))  =>  (t t t t)
[Note about case sensitivity: the lisp reader by default converts all symbol names to upper case as they are typed, so that internally symbol names normally contain only uppercase characters. The lisp printer by default prints these names in upper case. You can mess with both sets of behaviour if you care to, though heaven only knows why you would. Look up topics like readtables (that's another specialized data structure), *print-case* and section of the Hyperspec, if you care.]

9.6 Symbols and values

A symbol may or may not have a value associated with it. If you know the name of the symbol when you're typing, then "evaluating the symbol" will return the symbol's value.

(setf foo 99)  =>  99        ; setf always returns the [last] new-value
foo            =>  99        ; current value of the symbol foo
(1+ foo)       =>  100       ; etc
foo            =>  99        ; do not confuse 1+ with incf
If the name of the symbol is only available at run-time, you can still access its value by calling the setfable function symbol-value:
(symbol-value 'foo)         =>  99

(defun find-numb (symbols)
   (find-if (lambda (sym) (numberp (symbol-value sym)))
            symbols))       => find-numb

(find-numb '(foo bar baz))  => foo

(setf (symbol-value (find-numb '(foo bar baz))) "hello")  => "hello"

foo                         => "hello"

To discover whether a symbol does or doesn't have a current value definition (whether the symbol is bound), use the function boundp. To remove a symbol's value definition, call makunbound.
(boundp 'foo)   =>  t        ; the symbol foo currently has a value
(makunbound 'foo)            ; we remove that value...
(boundp 'foo)   =>  nil      ; ... and it's gone

(defun values-if-bound (symbols)
  (let* ((values nil))
    (dolist (sym symbols)
      (if (boundp sym)
          (push (symbol-value sym) values)))
    (reverse values)))
(setf bar 'yes wibble 'no wombat 'maybe)
(values-if-bound '(foo bar baz wibble wobble wombat))  => (yes no maybe)

If you attempt to get your hand on the value of a symbol while it is unbound, you get an error. Any [non-keyword - why?] symbol you've just created from scratch is initially unbound.
something-new   =>  Error: The variable SOMETHING-NEW is unbound....
9.7 Symbols and functions

Similarly, a symbol may or may not have a function associated with it. "Calling a symbol" as a function will invoke the appropriate function, if one has been defined.

(defun foo () t)  =>  foo    ; defun returns the symbol defined by it
(foo)             =>  t      ; nothing new so far, I hope
By analogy to symbol-value, boundp and makunbound, you can access the function associated with a symbol by calling symbol-function, ask whether it exists with fboundp, and remove it with fmakunbound. You can setf a symbol-function but the new value must be a function:

    (setf (symbol-function 'foo) (lambda (x) (bar (wibble x))))
    ;; foo will now have the same function definition as +
    (setf (symbol-function 'foo) '+)

9.8 Summary

Symbols, which we've been using heavily since the very beginning, are in fact data structures containing a number of fields. We have covered three of these here. We won't have time for packages or property lists (plists).
Permitted value
symbol-name A string No The print-name of the symbol, used to identify the symbol uniquely (within its package)
symbol-value Initially unbound. Can be any lisp object Yes The value associated with this symbol "as a variable"
symbol-function Initially unbound. Can be any function (named or anonymous, closure or not, etc.) Yes The function associated with this symbol
symbol-package An object of type package (or possibly nil) No, but see intern, import, export, etc. Packages form (somewhat) private namespaces. For example, the difference between foo and :foo is that they are in different packages
symbol-plist A list of the form (name1 value1 name2 value2 ...), initially nil. The names must be symbols, the values can be anything. Yes, but more usually accessed via setfable function get To allow you to hang additional values (properties) off a symbol

9.9 Practical session / Suggested activity

9.10 Further reading / exercises
Copyright (C) Nick Levine 1999. All rights reserved.
Last modified 2000-09-14
$Id: // $