opening it up with Common Lisp

Favorite weblogs

Lisp Related

Bill Clementson

Finding Lisp

Lemonodor

Lispmeister.com

Planet Lisp

Politics

Orcinus

Talking Points Memo

This Modern World

Working for Change

Other home

Polliblog

Recent Readings

Book review: Darwinia
Reviewed: Friday, August 11, 2006

Summer reading: Spin
Reviewed: Saturday, August 5, 2006

Runner
Reviewed: Tuesday, July 18, 2006

the Omnivoire's Delimma
Reviewed: Wednesday, July 12, 2006

the Golem's Eye
Reviewed: Wednesday, May 31, 2006





tinderbox
 width=

Class fusion
Thursday, July 8, 2004

Maybe it's just me, but I keep running into situations where the concrete classes in my system are composed of lots and lots of mixin classes from on high. Sometimes I handle this by using has-a instead of is-a and making each concrete instance a sort of manager who delegates its responsibilities out to its various mixins. Though flexible and a handy design "template" (dare I say pattern anymore), this can get to be a lot of work and involves some tedious bookkeeping. Therefore I sometimes do something completely different that most languages don't allow.

In Lisp, I can define new classes dynamically (and easily) and then make instances of them. When I want a new instance, I pass in a list of classes that the instance should inherit from (speaking loosely, I know instances don't inherit!). The creation function then tries to find an existing class that fits the need. If it finds one, it makes an instance of it and returns it. If an existing class cannot be found, it creates the new class and then makes an instance and returns it. It's almost like magic or, at least, like having your cake and eating it!

One quick example might make what I'm talking about more clear. My group has written a Common Lisp container library (which I'm going to package and put out there someday (soon (really))). To get an instance of a container, you call make-container:

(defgeneric make-container (class &rest args)
  (:documentation "Creates a new container of type 
class using the additional arguments (args).")
  (:method ((class symbol) &rest args)
           (apply #'make-instance class args)) 
  
  (:method ((classes list) &rest args)
           (let ((name
                  (or (u:find-existing-subclass
                       'abstract-container classes)
                      (u:define-class
                        (u:simple-define-class-name classes)
                        classes nil)))) 
             (apply #'make-instance name args))))

As you can see, calls to this with a symbol just go on and use make-instance. If, however, you pass in a list, magic happens. The find-existing-class function looks at all subclasses of abstract-container trying to find a existing class that inherits from all of the desired superclasses. If one cannot be found, then simple-define-class creates such a class on the fly (ain't Lisp cool!).

I've recently used this trick to add thread safety and some special printing capabilities to the container library. The thread safe code adds :around methods to acquire and release locks as necessary. Dynamic class creation makes it easy to add thread safety to existing container classes without creating a plethora of new classes that look like:

(defclass my-container-with-thread-safety
  (my-container 
   thread-safe-container-mixin)
  ())

Eventually, I'll get all this code out the under some Open Source license. If you have questions or comments before then, please let me know.


|

Home | About | Quotes | Recent | Archives

Copyright -- Gary Warren King, 2004 - 2006