Category Archives: Uncategorized

Exception handling in Lisp, as seen from C++, Part 1

In earlier series of articles, I’ve been talking about Lisp language features as they might appear to a C++ programmer.  I went over the power of Lisp macros, and talked about object-oriented programming in Lisp.

Now, we move on to exception handling, referred to in Lisp as conditions.  In the simplest case, conditions look like C++ exceptions.  The programmer wraps a piece of code in a “handler-case” block, the equivalent of try{} in C++.  Somewhere down the call stack, a function throws the exception, and the stack unwinds, looking for an exception handler at each level.  When it finds one, the unwinding stops, the handler is executed, and code continues after the handler (unless the handler itself throws another exception and the stack unwinding proceeds anew).  That’s what the simple case looks like in Lisp, but that’s not the true story, it’s just a one common programming model for conditions.

So, what really happens?  Well, conditions can be addressed by handlers or by restarts.  When a condition is signaled, the environment in which the code is executing is examined.  If the closest handler is a restart, the appropriate function is invoked.  Crucially, Lisp does not unwind the stack in this instance.  The restart runs as if called as a function from the point where the error occured (but with the restart handler unbound, so it won’t be called recursively if the restart signals the exception again).  The restart can, in fact, fix the error and allow flow to continue after the signal (the equivalent of the C++ throw).

With this available, the programmer can, at one point in the code, decide what to do about conditions signaled within the context.  (S)he can decide to operate on the error and then allow the code to continue from the point where the error was signaled, or cause the code to unwind the stack to a handler, or do nothing, and let the signals be controlled by the enclosing context.  While the code that signals the error generally has to be written with the possibility of restarts in mind, it does provide an interesting way to handle exceptional cases.

I will be providing examples in subsequent posts.

Formatting code for the blog

In case people were wondering how the code I’ve been posting has been formatted, here’s the procedure.

This blog is running on a WordPress installation.  I’ve installed the “Raw HTML” plugin.  This allows me to insert HTML directly into postings by surrounding them with “[raw]” and “[/raw]” in the text input mode.

I program in emacs, so I just needed an emacs package to convert the buffer to HTML.  I started out trying to use the built-in htmlfontify-buffer function, but it produced HTML with CSS elements that affected the rest of the page.  So, after looking around a bit, I settled on htmlize, which is available at this location.

So, load the code to be rendered, load the htmlize library, and run htmlize-buffer.  This creates a new buffer holding the HTML version of the displayed text, ready to be copied into the blogging software.

Object-oriented Lisp programming, as seen from C++. Part 3

Before I leave the topic of objects in Lisp vs. C++, I’ll bring up one more remarkable feature of Lisp.  This probably belongs to the category of things the C++ programmer never even imagined was a possibility.

It is possible, in a running Lisp instance, to redefine a class.  That is, the programmer can decide that a class was incorrectly implemented, and that it has to be redefined.  In this event, the programmer can supply code that lazily converts objects from the old class definition to the new one, without exiting the running instance.  Rather than describing the mechanics of this, I refer the interested reader to this page from the Common Lisp HyperSpec.

For a long-running, stateful C++ program, redefining classes would require saving state to disc, shutting down the binary, then starting the new binary and having it reload its state into the new classes.  It’s fairly remarkable that Lisp allows the programmer to define the conversion in the running core, so that it can simply lazily convert objects as they are encountered, allowing the program to continue running without interruption.

Object-oriented Lisp programming, as seen from C++. Part 2

So far, we’ve looked at simple generic functions, and how they compare to C++ methods.  There are, however, some generic functions that add interesting and useful features not obviously available in C++.  These include the :before, :after, and :around generic functions.

Looking at the code we supplied in the first part of this series, we see some duplicated code.  We create a new class for managed employees, and rebuild the hierarchy with those.  Then, we decide that as we further specialize the classes, the printing of them just adds further fields.  The new code now looks like this:

 
;; Polymorphism example

(defpackage :POLYMORPHISM
  (:use :COMMON-LISP)
)

(in-package :POLYMORPHISM)

(declaim (optimize (debug 3) (safety 3)))
; (declaim (optimize (debug 0) (safety 0) (speed 3)))


(defclass employee ()
  ((name                :accessor get-name
                        :initarg :name)
   (id                  :accessor get-id
                        :initarg :id)))

(defclass supervised-employee (employee)
  ((supervisor          :accessor get-supervisor
                        :initform nil
                        :initarg :supervisor)))

(defclass manager (supervised-employee)
  ((underlings          :accessor get-underlings
                        :initform nil
                        :initarg :underlings)))

(defclass underling (supervised-employee)
  ())

(defgeneric myprint (stream object)
  (:documentation "Prints to 'stream' some information about 'object'."))

(defparameter *printing-border* nil)

(defmethod myprint :around (stream (object employee))
  (when *printing-border*
    (format stream "~A~%" *printing-border*))
  (prog1
      (call-next-method)
    (when *printing-border*
      (format stream "~A~%" *printing-border*))))

(defmethod myprint (stream (object employee))
  (format stream "Employee name: ~A~%" (get-name object))
  (format stream "Employee ID: ~D~%" (get-id object)))

(defmethod myprint (stream (object supervised-employee))
  (call-next-method)
  (let ((supervisor (get-supervisor object)))
    (cond 
      (supervisor
       (format stream "Supervisor ID: ~D~%" (get-id supervisor)))
      (t
       (format stream "No supervisor~%")))))

(defmethod myprint (stream (object manager))
  (call-next-method)
  (format stream 
          "Supervising IDs:~{ ~D~}.~%" 
          (mapcar 'get-id (get-underlings object))))

(defmethod myprint (stream (object underling))
  (call-next-method))

(defun test-system ()
  (let* ((orc-1 (make-instance 'underling :name "Orc-1" :id 1))
         (orc-2 (make-instance 'underling :name "Orc-2" :id 2))
         (orc-3 (make-instance 'underling :name "Orc-3" :id 3))
         (orc-4 (make-instance 'underling :name "Orc-4" :id 4))
         (uruk-1 (make-instance 'manager :name "Uruk-1" :id 5 
                                :underlings (list orc-1 orc-2)))
         (uruk-2 (make-instance 'manager :name "Uruk-2" :id 6 
                                :underlings (list orc-3 orc-4)))
         (saruman (make-instance 'manager :name "Saruman" :id 7
                                 :underlings (list uruk-1 uruk-2))))
    (setf (get-supervisor orc-1) uruk-1
          (get-supervisor orc-2) uruk-1)
    (setf (get-supervisor orc-3) uruk-2
          (get-supervisor orc-4) uruk-2)
    (setf (get-supervisor uruk-1) saruman
          (get-supervisor uruk-2) saruman)

    (myprint t orc-1)
    (format t "~%~%")
    (myprint t orc-2)
    (format t "~%~%")
    (myprint t orc-3)
    (format t "~%~%")
    (myprint t orc-4)
    (format t "~%~%")
    (myprint t uruk-1)
    (format t "~%~%")
    (myprint t uruk-2)
    (format t "~%~%")
    (myprint t saruman)
    (format t "~%~%")))

Now, the myprint method for supervised-employee objects calls a function call-next-method.  This causes it to invoke, with the same arguments, the next defined method from a parent class, if any.  So, when the myprint method for manager objects is called, it first calls the myprint method for supervised-employee objects, which in turn calls the myprint method for employee objects.  In C++, one would do this with an explicit class name in the invocation.  There’s another defined method here, though, the :around method for employee objects.  This allows the programmer to insert an easy shim around the named method itself, where certain things could be done.  In this example, it optionally prints text above and below the record.  In other cases, it could be used to perform some sort of global sanity checking on passed arguments or returned values, or it could be used to insert a profiling or timing loop, without the need to scour through and edit the corresponding methods for all classes in the inheritance group.  This is a useful feature.  In fact, in some of my C++ code I’ve been known to write methods with an empty springboard function, purely so that I could add in general inspection code later in the style of an :around method.

It’s worth pointing out, too, that the myprint method for underling objects is entirely superfluous.  If that method were not defined, the invocation of myprint on it would look first for a supervised-employee method, and if there was none, would then look for an employee method.

The :before and :after methods are similarly useful, for taking action before or after a method is invoked.  A particularly useful one is to create an :after method for the initialize-instance method.  The initialize-instance method is the method that is invoked to construct objects.  It can fill in slots based on :initform or :initarg arguments, but doesn’t do more than that.  Think of it like the initialization list in a C++ constructor.  An :after method is like the body of the constructor.  It can take action based on the initialized slots.  This might include opening a file, building a data structure, or doing something more that, conceptually, you want as part of make-instance, but which is more complex than a simple assignment.

Object-oriented Lisp programming, as seen from C++. Part 1

For my job, I program in both Lisp and C++.  I use C++ much more than Lisp.  Looking at my previous series of posts, it seems I’m writing an introduction to Lisp for C++ programmers.  So, let’s go with that for a bit, and talk about the object system in Lisp.  I’m talking specifically about the CLOS, the Common Lisp Object System, which is a part of the ANSI Lisp standard.

To begin with, CLOS does not define member functions.  Instead, things that a C++ programmer would call non-member functions are used for polymorphism.  These are referred to as “generic functions”.  A CLOS generic function does not have special access to the members of a class, and does not have anything like the this pointer of C++.

Generic functions are declared in the namespace with defgeneric, and then defined for specific classes with defmethod.  This imposes an interesting restriction not present in C++ code.  All generic functions in the namespace must use the same API.  In C++ one could define several unrelated classes, each with its own PrintObject() public method.  Some might print to stdout, some might print to a user-supplied stream, some might return a string, some might take a record-separator as an argument, there need not be any consistency in the parameters passed to these distinct methods.  In Lisp, all generic functions must comply to their definition.  While it is possible to abuse this constraint, for instance by declaring that the generic function takes a single argument, a list, which itself contains the particular arguments that each specialized function will use, that would be bad practice, making the code less readable.

So, how is polymorphism achieved?  Let’s look at a code fragment.

 
;; Polymorphism example

(defpackage :POLYMORPHISM
  (:use :COMMON-LISP)
)

(in-package :POLYMORPHISM)

(declaim (optimize (debug 3) (safety 3)))
; (declaim (optimize (debug 0) (safety 0) (speed 3)))


(defclass employee ()
  ((name                :accessor get-name
                        :initarg :name)
   (id                  :accessor get-id
                        :initarg :id)))

(defclass manager (employee)
  ((supervisor          :accessor get-supervisor
                        :initform nil
                        :initarg :supervisor)
   (underlings          :accessor get-underlings
                        :initform nil
                        :initarg :underlings)))

(defclass underling (employee)
  ((supervisor          :accessor get-supervisor
                        :initarg :supervisor)))

(defgeneric myprint (stream object)
  (:documentation "Prints to 'stream' some information about 'object'."))

(defmethod myprint (stream (object employee))
  (format stream "Employee name: ~A~%" (get-name object))
  (format stream "Employee ID: ~D~%" (get-id object)))

(defmethod myprint (stream (object manager))
  (format stream "Employee name: ~A~%" (get-name object))
  (format stream "Employee ID: ~D~%" (get-id object)))
  (format t "~%")
  (let ((supervisor (get-supervisor object)))
    (cond 
      (supervisor
       (format stream "Supervisor ID: ~D~%" (get-id supervisor)))
      (t
       (format stream "No supervisor~%"))))
  (format stream 
          "Supervising IDs:~{ ~D~}." 
          (mapcar 'get-id (get-underlings object))))

(defmethod myprint (stream (object underling))
  (format stream "Employee name: ~A~%" (get-name object))
  (format stream "Employee ID: ~D~%" (get-id object)))
  (format t "~%")
  (let ((supervisor (get-supervisor object)))
    (cond 
      (supervisor
       (format stream "Supervisor ID: ~D~%" (get-id supervisor)))
      (t
       (format stream "No supervisor")))))

(defun test-system ()
  (let* ((orc-1 (make-instance 'underling :name "Orc-1" :id 1))
         (orc-2 (make-instance 'underling :name "Orc-2" :id 2))
         (orc-3 (make-instance 'underling :name "Orc-3" :id 3))
         (orc-4 (make-instance 'underling :name "Orc-4" :id 4))
         (uruk-1 (make-instance 'manager :name "Uruk-1" :id 5 
                                :underlings (list orc-1 orc-2)))
         (uruk-2 (make-instance 'manager :name "Uruk-2" :id 6 
                                :underlings (list orc-3 orc-4)))
         (saruman (make-instance 'manager :name "Saruman" :id 7
                                 :underlings (list uruk-1 uruk-2))))
    (setf (get-supervisor orc-1) uruk-1
          (get-supervisor orc-2) uruk-1)
    (setf (get-supervisor orc-3) uruk-2
          (get-supervisor orc-4) uruk-2)
    (setf (get-supervisor uruk-1) saruman
          (get-supervisor uruk-2) saruman)

    (myprint t orc-1)
    (format t "~%~%")
    (myprint t orc-2)
    (format t "~%~%")
    (myprint t orc-3)
    (format t "~%~%")
    (myprint t orc-4)
    (format t "~%~%")
    (myprint t uruk-1)
    (format t "~%~%")
    (myprint t uruk-2)
    (format t "~%~%")
    (myprint t saruman)
    (format t "~%~%")))

This is a brute-force approach to the problem, one that we will refine in later postings.  We have declared that the myprint method takes two arguments.  The first is an output stream, the second is the object to be printed.  Which particular generic function is called depends on the object passed.  By default, the most specialized generic function is selected.  So, even though we have defined a method that prints out the base class, employee, when we ask to print an underling or manager object, the corresponding more specialized method is used.

This, though, is only the beginning.  We will extend this somewhat in a later post, before moving on to other CLOS behaviour.