opening it up with Common Lisp
Book review: Darwinia
Summer reading: Spin
the Omnivoire's Delimma
the Golem's Eye
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
(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
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.
Copyright -- Gary Warren King, 2004 - 2006