setup-swank: an example of a self-modifying function

This post came from a short-lived blog I tried to run (tail-recursion.net) where I wanted to write up a short bit of code I'd written that week.

This function sets up a toggleable swank listener in a Lisp program. This enables a REPL directly in the running process, providing unparalled introspection, debugging, and speed of development. It performs some initial setup, sets up a closure over a status variable, and then swaps out the setup code for the production code.

    (defun start-swank (&key (port 4006))
      "Setup a swank server in the running process."

The swank-running-p variable is used to keep track of the function's state: is swank running?

      (let ((swank-runningp nil))

We create a new, locally-scoped function.

        (labels ((fn ()
                     (progn
                       (if swank-runningp
                           (progn

If swank is running, we print a message to the console alerting the programmer that swank is shutting down.

                             (format t "Stopping swank server...~%")

Then, stop swank.

                             (swank:stop-server port)

Finally, update the swank status variable.

                             (setf swank-runningp nil))
                           (progn

If swank is not running, let the programmer know that it is being started.

                             (format t "Starting swank server on port ~A.~%" port)

Start the server, and make sure that it doesn't close when the function exits.

                             (swank:create-server :port port :dont-close t)

Finally, update our status.

                             (setf swank-runningp t)))

After taking the appropriate action, we'll return the current swank state so that it can be programmatically acted on.

                       swank-runningp)))

Swap out the setup code for our locally defined function.

          (setf (symbol-function 'start-swank) #'fn)

The function is called start-swank, so we start swank.

          (start-swank))))

The untransformed code is available.


Tags: ,