UP | HOME

LambdaMOO

The LambdaMOO programming environment was1 very pleasant to work in despite being somewhat dinky, with its strange ALGOL-style programming language. The LambdaMOO server being what it was, I don’t think it was ever really used for anything ‘serious’ (most of the programs written in MOO are probably little entertaining toys and games).

Despite this, it was very well-designed. Unsurprising when you consider who was behind it — apparently Kent Pitman worked on it at one point, and even recommended learning MOO as an example of a secure and persistent language.

MOOs underwent something of an Indian summer around 2004–6 which is when I had my experiences with them.

There is a ‘new implementation’ of the LambdaMOO server in Haskell called EtaMOO which looks interesting.

Features of MOO

The whole environment was networked (naturally) and persistent. It was like a giant Smalltalk image shared by everyone; or a networked Emacs with co-operative multitasking.

Because of this, library functions could be written by one person and then used by everyone. There were some very nice ones that came with LambdaCore, and more included with the various derivative Cores that most latter-day MOOs used. Like in Emacs, library functions and interactive commands existed in the same namespace and were distinguished by a special flag (although admittedly I recall it was somewhat tricky to write one ‘verb’ which could be used as both2).

The most useful libraries of functions were ‘corified’ i.e. integrated into the core database (by setting a property on the root object of the database) which gave them a convenient global name. If you wanted to use a library outside this set (though you hardly needed to in my experience, since most admins had configured an ample variety) you could set a property on your own object containing the ID of the object holding the library functions, and then you could access it in a convenient similar manner.

It was also possible for system administrators to patch the core functions of the server (written in C) with replacements written in MOO code.

Since the server had no hash table or other dictionary type built in, you had to use association lists. Here’s an example of a library function (called $list_utils:assoc) which looks up a key in an alist and returns the {key, value} pair containing it.

1: "assoc(target,list[,index]) returns the first element of `list' whose own index-th element is target.  Index defaults to 1.";
2: "returns {} if no such element is found";
3: {target, thelist, ?indx = 1} = args;
4: for t in (thelist)
5:   if ((typeof(t) == LIST) && `t[indx] == target ! E_RANGE => 0')
6:     return t;
7:   endif
8: endfor
9: return {};

Lines 1 and 2 comprise the docstring, available online interactively at any time by just typing help $list_utils:assoc. Line 3 is a ‘spread assignment’ in modern parlance, which extracts named arguments from the argument list passed to the function. (Notice how it’s possible to have an optional component in a spread assignment.)

Line 5 contains a bit of a trick. Lists in MOO were 1-indexed and there was no boolean type, 0 being the canonical false value.3 After checking that the current item in the association list is actually a sublist, it looks at the desired index in the sublist (by default 1 i.e. the first element) and checks if it’s the desired key. The strange backtick and exclamation mark syntax is a try/except expression — i.e. if looking for the key returns E_RANGE (a list index out of range error), evaluate to false.

Apart from having no dictionary type available, there was also no way to put control characters in strings, including newlines. Multi-line strings were actually lists of strings.

To prevent excessive resource use, every program could only execute a certain number of VM instructions before it was killed. You could get around that by calling the sleep function which reset your tick counter; there was, of course, a library function that would check if you were running out of ticks and call it for you if you were. Every user had a limited quota for their objects, which could either be based on counting the objects themselves or estimating their actual size in bytes.

Security was handled in an interesting way: in Unix terms, every interactive function was setuid to the person who wrote it. So if you didn’t want people running weird code on your account, don’t write that code! (You could make functions ‘private’ for your own use by calling a function that gave you an inspectable stack trace and making sure your callers were trusted.)

The object database was prototype-based, with a few bits and bobs to make it more like a class-based system. Only objects with a +f flag could be cloned; those with this flag set were then usually considered ‘generic’ examples of their class. For instance, if I made a prop for the virtual environment called ‘generic kettle’, I would then set +f, clone it and create ‘dpk’s kettle’, and anyone else could make their own kettle in the same way.

Positives

  • Intrinsically networked, collaborative, and social
  • A persistent object database as storage for all data and code
  • Diverse range of functions available in the standard library of most database cores
  • Encouraged code-sharing through a global object naming and numbering system
  • Some good tools for reflection and code inspection

Negatives

  • Limited set of data types (integer, float, string, list, object-reference)
  • Programming language somewhat underpowered (e.g. no lambdas)
  • Object creation expensive, especially given quota restrictions
  • Only suitable for creating line-oriented applications

Footnotes:

1

I’m going to be using the past tense throughout because it seems to me that MOO is basically dead. I can’t find any active servers other than the original one, and even that seems to be just a few long-idle old-timers.

2

Because the interactive interface was based on an interactive-fiction–style pseudo-natural language parser, the arguments to interactive functions were in the form of a direct object, a preposition, and an indirect object. Functions which were never interactive were created with the argument signature ‘this none this’ (which you could abbreviate as ‘tnt’), meaning the object which defined the verb, followed by no preposition, followed by the same object. The natural language parser was incapable of producing function calls with such a signature so the verb was then effectively hidden from non-programmers.

3

This was used to good effect by the ‘in’ operator, which took a datum as its first operand and a list as its second. If the datum was in the list, it returned its first index; otherwise it returned 0. It could thus be efficiently used as both a test for an item’s presence as well as a way to find the position of that item.