In the last entry, I wrote a bit about the basics of how object instantiation and property/slot access works in Sheeple. In this entry, I’ll introduce a whole different realm of Sheeple: the method dispatch system. If you’re familiar with Javascript, it might already be obvious to you how polymorphic method dispatch can be implemented with the small bit of Sheeple we know so far:
SHEEPLE-USER> (add-property *sheep* 'foo (lambda () (print "Method called!"))) #<Sheep #x15031356> SHEEPLE-USER> (foo *sheep*) #<Anonymous Function #x1506C446>
For those confused: the above equivalent in javascript would be:
sheep.foo = function () { alert("Method called!"); }
sheep.foo -> function object
And there you have it. Actually calling the function is just a matter of using Lisp’s version of adding () at the end of a variable:
SHEEPLE-USER> (funcall (foo *sheep*)) "Method called!"
In JS:
sheep.foo(); => an alert pops up. The method was called.
Nothing new here. It’s cute and all, but Sheeple has a much nicer facility for defining ‘methods’. I’ve opted to call these “Messages/Replies.” For those familiar with CLOS, the basic concept is exactly like Generic Functions/Methods. In fact, I would have named them the same thing, but I wanted to be able to operate in parallel with CLOS — which I do regularly. The big deal about these message/replies is that, instead of dispatching on a single value (whichever object holds the function that will be called), method lookup involves 0 or more arguments. The semantics, of course, end up being more complex than the singly-dispatched approach, but it opens up a world of possibilities and expressive power (not to mention completely obsoletes the Visitor pattern).
The concept of messages/replies is as follows: You have something called a ‘Message’ that works like a generic dispatcher. It defines the basic idea of what arguments to this function should look like, and it defines which arguments will be dispatched on. It does some other things, but the important part here is that Messages work like interfaces (no-implementation definitions) for replies that will be defined.
In Smalltalk terms, a Message is passed to not necessarily just one object, but to multiple objects, and the code that is run is whatever the collective Reply they agree on to that message is.
SHEEPLE-USER> (defmessage synergize (a b))
#<Message: SYNERGIZE #x150A23DE>
This gives us an empty message. As far as Lisp is concerned, it can be called just like any function.Right now, though, it won’t be able to do anything, (It will signal an error saying there are no applicable replies) because we haven’t defined any replies for it, so let’s define one.
SHEEPLE-USER> (defreply synergize ((a (proto 'number))
(b (proto 'number)))
(+ a b))
#<Reply: SYNERGIZE #x150433F6>
This reply specializes the arguments A and B on (proto ‘number), which is an abstract object that represents all numbers. This means that if SYNERGIZE is called with its first and second arguments being numbers, the body of this reply will execute.
SHEEPLE-USER> (synergize 5 2)
7
We did numbers, but what does it mean to ‘synergize’ strings?
SHEEPLE-USER> (defreply synergize ((a (proto 'string)) (b (proto 'string))) (concatenate 'string a b)) #<Reply: SYNERGIZE #x150B4A76> SHEEPLE-USER> (synergize "foo" "bar") "foobar"
So far so good. Now we can start mixing and matching and seeing what kind of behavior we end up with. A more
SHEEPLE-USER> (defreply synergize ((a (proto 'string)) b) (concatenate 'string a (format nil "+object: ~A" b))) #<Reply: SYNERGIZE #x150B49F6> SHEEPLE-USER> (synergize "foo" 45) "foo+object: 45"
By not wrapping our parameter in parens, we default to the toplevel object in the Sheeple hierarchy: (proto ‘t). This means that this reply will be applicable when -any- lisp object is given as the second argument to SYNERGIZE. This is essentially single-dispatch, except our old string-string reply will still apply, since it’s more specific than this general one:
SHEEPLE-USER> (synergize "foo" "bar") "foobar"
As a note: dispatch is left-weighted, so higher specificity to the left of the argument list (lambda list in lisp terms) will outweigh higher specificity in arguments to its right. The algorithm itself is based on Slate‘s description of Prototype Multiple Dispatch (PMD, take a look at Fundamentals). Sheeple supports much more than what I’ve shown. It has :before, :around, and :after replies (which have identical semantics to the way CLOS handles them), and has a mechanism for handling &key, &rest, &optional, and company (which, again, works identical to CLOS’ facilities).
The big difference, in the end, between CLOS and Sheeple is that Sheeple dispatches everything on actual objects. It’s like defining all CLOS methods with EQL specializers in a world where the objects themselves hold the hierarchy. The biggest implication of this, I think, is that the hierarchy never bottoms out — and that’s quite useful when you’re developing.
Next time, I’ll start talking about how development with Sheeple actually works. I’ve written a couple of applications using it, and there’s been some good lessons learned from those — which have then reshaped the way Sheeple works. Questions so far? Leave a comment! Or just check out Sheeple’s documentation.

The Sheeple continued: Dispatch by sykosomatic, unless otherwise expressly stated, is licensed under a Creative Commons Attribution 3.0 Unported License.