WAIF Datatype

The WAIF datatype is a patch to the LambdaMOO server. It adds support for a new type of value called a WAIF. The WAIF branch on sf.net CVS has the latest code and is based on the 1.8.2 server.

The code was written by Ben Jackson.

You can download the patches here. Note that there will be a couple of rejects in LambdaMOO 1.8.1, you will have to make a few one-line changes by hand.

You may also want to read my original description

What is a WAIF?

It's a lightweight object. It is a value which you can store in a property or a variable or inside a LIST or another WAIF.

What do you mean lightweight?

I mean it is smaller in size (measured in bytes) than a regular object, and it is faster to create and destroy. It is also reference counted, which means it is destroyed automatically when it is no longer in use.

What do you mean smaller?

On a 32 bit machine like an i386, the smallest possible OBJ object is about 100 bytes. In a LambdaCore derived database this would be the size of a child of $garbage (i.e. Recyclable #1234). A typical OBJ descended from #1 is larger because there are more properties to inherit, about 176 bytes.

In contrast, an empty LIST is 16 bytes (according to value_bytes({})) and an empty STR is 9 bytes. A WAIF with no properties set (as long as the class does not define more than about 100 properties) is 36 bytes.

Since a WAIF has two builtin OBJ properties, .class and .owner, you can compare it to a LIST of {class, owner}, which is 32 bytes.

So a WAIF is pretty small.

OBJs grow by value_bytes(value) - value_bytes(0) [why] for every propery you set (that is, every property which becomes non-clear and takes on its own value distinct from the parent). LISTs and WAIFs both grow by value_bytes(value) for each new list element (in a LIST) or each property you set (in a WAIF). So a WAIF is never more than 4 bytes larger than a LIST which holds the same values, except WAIFs give each value a name (property name) but LISTs only give them numbers.

What do you mean faster?

I mean it is faster to create and destroy WAIFs than OBJs. I should measure this, but I haven't gotten around to it (well, actually, I got around to it years ago and forgot the exact results). A WAIF costs about as much as a LIST to make. Creating objects (or, more likely, using a db verb to chparent() an object from $garbage for you is more expensive. It also invalidates the verb lookup cache.

Essentially you should consider a WAIF as something you can make thousands of in a verb without a second thought. You might make a mailing list with 1000 messages, each a WAIF (instead of a LIST) but you probably wouldn't use 1000 OBJs.

What do you mean reference counted?

You create and destroy OBJs explicitly with the builtins create() and recycle() (or allocate them from a pool using verbs in the core). They stay around no matter what you do until you destroy them.

All of the other types you use in MOO (that require allocated memory) are reference counted. However you create them, they stay around as long as you keep them in a property or a variable somewhere, and then they silently disappear, and you can't get them back.

Why/when would I want to use WAIFs?

As I described above a WAIF is never more than 4 bytes longer than a LIST with the same values. But you get nice names for each value and you have a way to call verbs associated with the function of the list. Why use subj = message[1] when you can have subj = message.subject?

In other words, use a WAIF whenever you want to collect values together and give each value a meaningful name instead of just an index into a LIST. WAIFs are ideal for replacing alists where the set of alist keys is fixed, since you still get to call every value by name but you only have to keep the list of keys in one place.

Why would I want WAIFs in my server?

If you are running a development MOO, especially with a lot of core hacking, you might find WAIFs very handy for implementing infrastructure like messages, player options, features, coordinate systems, webservers, replacement parsers, component object systems, etc.

Will WAIFs ever be in the mainline server?

I'm one of the server maintainers, so I can at least guarantee that WAIFs won't be broken by new server versions. But despite the fact that they are nearly 3 years old, WAIFs haven't had as much exposure as I would like so they will probably not make it into the mainline server without more feedback from users.

How do I get started with WAIFs in my server?

You'll need some core changes to make it easier to manipulate WAIF properties (which start with :), notably in $code_utils:parse_verbref which needs to know that a string like foo.:bar is a property :bar on foo rather than a verb bar on foo.. You can also play games with :isa and valid() depending on your application. Also, if you want to sneak them in where OBJs go (like into pronoun_sub) you may have places that need to change from explicit testing like typeof(x) == OBJ ? x.y | ... to just try it with error handling: `x.y ! E_PROPNF, E_INVIND => ...'.

Make an object to serve as a WAIF class. You can make a special root WAIF to be the parent of all WAIF classes for convenience, and call it $waif. It doesn't matter what this object is a child of, because the WAIFs you make from it only inherit properties and verbs with names that start with colon (:).

New WAIFs are only created by a builtin called new_waif(). It takes no arguments because it always makes a new WAIF with the class equal to the object that calls new_waif(). So your first verb is $waif:new:

2:  set_task_perms(caller_perms());
3:  w = new_waif();
4:  w:initialize(@args);
5:  return w;
You'll notice line 4 calls a verb on the new WAIF. Because of the translation rules, this runs the verb $waif::initialize. This is just for convenience. The version I use doesn't do anything, it just documents a boilerplate for WAIF class makers to use:
1:  // the perms check you want is probably:
2:  if (caller == this || caller == this.class)
3:    // allows pass() and :new()
4:  else
5:    raise(E_PERM);
6:  endif
Notice how in line 2 the variable THIS contains the WAIF. To find the OBJ with these verbs you can use this.class.

Now you can make a chlid of $waif and call child:new() which will return a WAIF with waif.class == child. Now make child.:properties and child::verbs to use on the WAIFs you make from it.

How do I get started with WAIFs as a programmer?

If your core has a $waif make a child of that. Add properties to it like:
> @create $waif named my waif class,class
> @prop class.:x 0
> @prop class.:y 0
> @prop me.tmp 0 ""
> #class
=> #1234
> ;me.tmp = #1234:new()
=> [[class = #1234, owner = #100]]
> ;me.tmp.x
=> 0
> ;me.tmp.x = 57
=> 57
> ;me.tmp.x
=> 57
> @verb class::length this none this rxd
> @prog class::length
> return sqrt(tofloat(this.x) ^ 2 + tofloat(this.y) ^ 2);
> ;me.tmp:length()
=> 57.0
> ;me.tmp.y = 91
=> 91
> ;me.tmp:length()
=> 107.377837564369

Where can I play with this stuff?

I usually have a devmoo up at place.org:7777 with free player creation to play with these things. Or you can find me on Waterpoint or even YibMOO, which recently added WAIFs to their server.

More Information

You may also want to read my original description which has some more detail comparing MOO value types and describing the property/verb translation.

Footnote: Why OBJs Grow Like They Do

An OBJ starts out with a list with enough slots to hold one value for each property it defines or inherits. So think of a brand new OBJ like a list of {0, 0, 0, ...}. When you set a property value you replace the 0 with another value, so the size only goes up by value_bytes(value) - value_bytes(0).