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
$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.
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.
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.
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.
$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
:
You'll notice line 4 calls a verb on the new WAIF. Because of the translation rules, this runs the verb1: // WIZARDLY 2: set_task_perms(caller_perms()); 3: w = new_waif(); 4: w:initialize(@args); 5: return w;
$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:
Notice how in line 2 the variable1: // 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
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.
$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
{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)
.