I wrote a another description here.

The patches are available as waif-0.95.tgz.

NOTE FOR MOO-1.8.1 USERS: You will get two diff hunks rejected, one for Makefile.in and one for tasks.c. You must merge these by hand. They are both one line changes. Most critical is the tasks.c change which will not prevent you from compiling but would eventually lead to a server panic.

The WAIF datatype is a patch to the LambdaMOO server. The WAIF branch on sf.net CVS has the latest code and is based on the 1.8.2 server.

WAIF Programmers' Manual

Introduction

The MOO object structure is unique in that all classes are instances and all instances are (potentially) classes. This means that instances carry a lot of baggage that is only useful in the event that they become classes. Also, every object comes with a set of builtin properties and attributes which are primarily useful for building VR things. My idea of a lightweight object is something which is exclusively an instance. It lacks many of the things that "real MOO objects" have for their roles as classes and VR objects: Stripped to its core, then, a WAIF has the following attributes:

What is a WAIF?

A WAIF's properties and behavior are a hybrid of several existing MOO types. It is instructive to compare them:

The WAIF verb/property Namespace

In order to separate the verbs and properties defined for WAIFs of an object, WAIFs only inherit verbs and properties whose names begin with : (a colon). To say that another way, the following mapping is applied:
waif:verb(@args) becomes waif.class:(":"+verb)(@args)
Inside the WAIF verb (hereinafter called a method) the local variable verb does not have the additional colon. The value of this is the WAIF itself (it can determine what object it's on with this.class). If the method calls another verb on a WAIF or an OBJ, caller will be the WAIF.
waif.prop is defined by waif.class.(":"+prop)
The property definition provides ownership and permissions flags for the property as well as its default value, as with any OBJ. Of course the actual property value is part of the WAIF itself and can be changed during the WAIFs lifetime.

In the case of +c properties, the WAIF owner is considered to be the property owner.

An Example Object, $waif

Here's @display output for a skeletal $waif, plus some additional properties for the sake of example:
root waif (#234) [ readable fertile ]
  Child of root class (#1).
  Location Ben (#2).
  #234:new                      Ben (#2)             rxd
  #234::initialize              Ben (#2)             rxd
.type                    Ben (#2)              r      10
.:example                Ben (#2)              r      "hello"
.:plusc                  Ben (#2)              r c    {1, 2, 3}
--------------------------- finished ----------------------------
This MOO OBJ defines 2 verbs and 3 properties (and inherits many others, which we are simply ignoring here). It defines a verb new which is just like the verbs you're already familiar with. In this case, it creates a new WAIF:
 1:  set_task_perms(caller_perms());
 2:  w = new_waif();
 3:  w:initialize(@args);
 4:  return w;
The new_waif() builtin creates a new WAIF whose class is the calling object and whose owner is the perms of the calling verb. This wizardly version causes it to be owned by the caller of the verb.

Once the WAIF has been created, you can call verbs on it. Notice how the WAIF inherits $waif::initialize. Notice that it cannot inherit $waif:new because that verb's name does not start with a colon.

The newly created WAIF has two properties, one named example and one named plusc. Their default values are inherited from the object. The example property is +r and can be read by anyone, but only Ben (#2) can write to it. The aptly named plusc property is +c and is owned by the WAIF owner (whoever the caller of $waif:new() is, in this example).

There's also a $waif.type property which has the numeric value returned by typeof(new_waif()). This doesn't change the output of typeof(). This is just someplace in the db to contain the constant that would be a WAIF variable (like STR or FLOAT) if I had added one. This is just an ordinary property. Nothing to see here.

The generic waif is fertile ($waif.f == 1) so that new waif classes can be derived from it. OBJ fertility is irrelevant when creating a WAIF. The ability to do that is restricted to the object itself (since new_waif() always returns a WAIF of class=caller).

References to WAIFs

There is no string format for a WAIF. tostr() just returns {waif}. toliteral() currently returns some more information, but it's just for debugging purposes. There is no towaif(). If you want to refer to a WAIF you have to read it directly from a variable or a property somewhere. If you cannot read it out of a property (or call a verb that returns it) you can't access it. There is no way to construct a WAIF reference from another type.