Introduction to Sheeple

For a few months now, I’ve been working on something I call Sheeple. What is Sheeple? From the
official description:

Sheeple is a Dynamic, CLOS-like, Delegative Prototype-based Object-Oriented Programming
Framework (or “POOP Framework”) that strives to optimize application flexibility, minimize cost
while increasing value, maximize programmer resources, and empower application implementers to
better assist them in leveraging modern paradigms in order to proactively achieve next-generation
synergy in tomorrow’s web 3.0 world. It is implemented in (mostly) ANSI Common Lisp. Sheeple is
fully buzzword compliant.

Now that doesn’t really say much of anything, but it’s
amusing, specially since some actual (professional!) projects actually describe things in such a
way.

What does it actually do, though?

Well, Sheeple is a library for Common Lisp that implements a Prototype-based object-oriented language very similar to Common Lisp’s standard CLOS. It does things like multiple dispatch, multiple inheritance and such.

One goal I had while designing it was to have it be as practical as possible. Javascript is making waves around the internet these days — not just because it’s the de-facto standard browser-scripting language, but because it’s prototype-based.

The idea of having a prototype-based language instead of using classes for OO is nothing new. Even so, it seems like there’s still debate about the merits of using prototypes instead of classes. In fact, some prototype-based languages, specifically Javascript, have libraries that implement classes!

Even though there are various languages to choose from, there are still few languages that provide what I would consider full facilities. Cecil seems to be one of those ‘full’ languages, but I really ended up disliking its approach — it was too complicated, and there were too many obvious minefields. Sheeple is an attempt at providing the kind of massive framework CLOS provides for class-based OO, but with prototypes, while remaining easy-to-use, straightforward, and most importantly, convenient. Whether it’s successful at this right now (it’s still in development after all), and whether it will ever be is a different question. ;)

Here’s some basic sample code, from the docs:

The CLONE function called with no args creates a regular sheep object with DOLLY as its only parent object.

SHEEPLE-USER> (defparameter *my-sheep* (clone))
*MY-SHEEP*

Sheeple (I refer to single objects as ‘a sheep’, and multiple objects as ‘sheeple’) are, at the basic level, simply glorified hash tables: key/value stores that can be changed at runtime. Every property a sheep object has is named by a symbol.

SHEEPLE-USER> (add-property *my-sheep* 'var "value")
#<Sheep #x1508F91E>
SHEEPLE-USER> (var *my-sheep*)
"value"

A relationship hierarchy in the style of super/subclasses is created by simply cloning an existing object.

SHEEPLE-USER> (defparameter *child* (clone *my-sheep*))
*CHILD*

You can think of the way this new object works as “It’s just like its parent, but X, Y, and Z are different.”
This is called differential inheritance. Sheeple, unlike other languages that follow the prototype model for OO, such as Slate or Self, does differential inheritance by default, making it more like Io in that sense.
To understand how differential inheritance works, look at this example:

SHEEPLE-USER> (var *child*)
"value"

Here’ we can see that the value of child’s VAR property is the same value that *my-sheep* had in that property.
The funky awesome stuff comes when we change the parent object in some way:

SHEEPLE-USER> (setf (var *my-sheep*) "new-value")
"new-value"
SHEEPLE-USER> (var *my-sheep*)
"new-value"
SHEEPLE-USER> (var *child*)
"new-value"

As you can see, changing the value of one of the parent object’s properties changes the value *child* sees whenever it tries to access that property. This maintains the “*child* is just like *parent* relationship, although it has some other benefits that I like (which I’ll discuss in a later post about differential inheritance).

But what if we never intended for *child*’s var property to change?
In that case, all we would have to do is set that property in *child*, and the change in *my-sheep* would never have affected it.

SHEEPLE-USER> (setf (var *child*) "my-own-value"
"my-own-value"
SHEEPLE-USER> (var *child*)
"my-own-value"

In general, the design I’m aiming for is “parents can change their own behavior, which can affect children, but they cannot directly touch the children, nor can children touch them”… or something like that. The truth is that differential inheritance can be a bit tricky to understand, and there’s some major caveats. Once you really get why it’s useful, and know how to avoid pitfalls, though, I think it can turn into a genuinely useful tool.

In a later post, I’ll write about Sheeple’s method dispatch mechanism, which is based on Slate’s PMD, and why you want it. If you’re too impatient, just check out Sheeple’s code on github, and skim through doc/user-guide.org, which is a bit of a working spec of a good chunk of the language.

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

This entry was posted in programming and tagged , , , , . Bookmark the permalink. Follow any comments here with the RSS feed for this post. Post a comment or leave a trackback: Trackback URL.
  1. Adlai says:

    This is all very interesting… I just thought there should also be mention of applications using Sheeple:

    Sykosomatic —
    Sykobot —

    See for yourself: Sheeple works!

    Sykoedit: This doesn’t sound astroturfy at -all-, amirite?

  2. foo says:

    How is it different from Object Lisp?

    • sykopomp says:

      http://www.mactech.com/articles/mactech/Vol.06/06.08/PearlLisp/index.html Is an interesting overview of Object Lisp.

      From what I can tell, Object Lisp also does differential inheritance. The two biggest differences I’ve noticed so far, though, are:

      1. Object Lisp is singly-dispatched — you declare methods (objfuns) on single existing objects. Sheeple does multiple dispatch with semantics like CLOS.

      2. OL keeps ‘class’ objects in the same namespace, apparently in dynamic variables? Sheeple has a separate namespace for all ‘class’ objects (which are called protos). Sheeple itself doesn’t make a distinction between the objects themselves, and the defproto form is there mostly for how convenient it is for lisp-style interactive development (you can re-evaluate the form, and the object is mutated while retaining identity). I’m not sure exactly how defobject works.

      Those seem to be the two most obvious differences. I’m sure digging in would oust more stuff.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>