Monday, August 2, 2010

Events for Lazy Lisp Programmers...

Events are an important part of my Qix idea. But most event systems require quite a bit of code. In object oriented designs, an event handling class is created and you can inherit other classes from it. Which is fine, if you want to hard-code event types and only call designated objects. But Lisp always seems to hint at a more efficient way of doing things. With HTML and Javascript as my examples I decided to try something different. I started with a hash:

(setf *handler-hash* (make-hash-table :test 'eq))

Then I made a couple of simple functions:

(defun register-handler (obj handler)
(setf (gethash obj *handler-hash*)
(append (gethash obj *handler-hash*) (list handler))))

(defun fire (object &rest e)
(let ((handlers (gethash object *handler-hash*)))
(loop
for i in handlers
do (setf e (apply i e))
while e)))


Now, with these two functions I can create events for any object. As long as the (eq... test says they are the same. So lets take *standard-input*:

(register-handler *standard-input* (lambda (&rest x)
(format t "I was passed: ~A~%" x)
'(world)))

(register-handler *standard-input* (lambda (&rest x)
(format t "I was passed: ~A~%" x)
'(goodbye)))

(register-handler *standard-input* (lambda (&rest x)
(format t "I was passed: ~A~%" x)
'nil))

(register-handler *standard-input* (lambda (&rest x)
(format t "I was passed: ~A~%" x)
'(anyone still here?)))

And then fire an event with (fire *standard-input* 'hello)...

I was passed: (HELLO)
I was passed: (WORLD)
I was passed: (GOODBYE)

You get the idea. Here, events can modify the following events, and even stop the event chain altogether. Of course there are many other considerations such as unregistering events and such, but this is still a lot of functionality in two small functions and a hash table!

No comments:

Post a Comment