MLud is an object-oriented, prototype-based language designed for building on-line collaborative environments and other runtime-extensible systems. Its compiler and runtime environment are both implemented in Standard ML. It possesses a variety of features targeted towards the types of situations in which it is commonly used. These include:
MLud, like Smalltalk, is a fully object-oriented language. Even the built-in types each delegate to an object, and nearly all operations are implemented as method calls, so that even the most basic behaviour in the system is fully customizable. Because the language is prototype-based, even what would normally be classes are objects which can be manipulated and examined, which constitutes a limited form of reflection.
Like Self, Cecil, and some other languages, and unlike Java, C++, or Smalltalk, MLud does not have the separate concepts of classes and instances. Instead, there are only objects, which delegate messages to a fixed set of other objects called their parents.
Thus, a class is represented in MLud as an object, complete with state, while the equivalent of its instances delegate to the class object, except that functionality can be added to the "instances", and new objects can, in turn, delegate to them. The resulting structures allow high flexibility at run-time, and foster fast prototyping and better conceptual models of the system.
Dynamic delegation, supported in Smalltalk but not in Java, C++, or Cecil, is a mechanism allowing the construction and modification of object delegation hierarchies at runtime. In other words, you can change the parent object of an object, radically changing its behaviour, or add new parents to add new behaviour. When used properly, dynamic delegation provides a powerful mechanism for extending objects in the system.
A MLud program is fully runtime-extensible. What this means is that at any time during the run, you can add new objects, add new methods to objects based on a string containing MLud code, remove methods, change delegation hierarchies, and even modify every detail of the functionality of the runtime system and the MLud compiler itself. Because of this, a system can evolve over a long period of time without ever ceasing to run, crucial in collaborative development environments.
Being based entirely on vanilla SML/NJ and MLud itself, MLud is as portable as the SML/NJ system, which runs on a variety of platforms, even Windows.
Multiple dispatch is a relatively rare feature, currently
most notably found in Cecil, which expands on the polymorphism of
method calls found in most object-oriented languages. While
these languages allow the runtime to choose which method will
be called based on the type of the object the method is called
on, multiple dispatch allows the method to be chosen based on
this as well as the number and type of all the other
arguments. This helps separate the treatment of arguments of
various types into a hierarchy of methods for handling them;
for example, the integer object has separate methods
for adding other integers and reals.
Simple exceptions are supported. Any object can be thrown, and it will be caught by the first handler that handles it or an ancestor of it. An exception object in the system library provides the additional functionality of generating stack traces for debugging purposes which the user who caused the offending exception can view.
A common downfall in building any runtime-extensible language is that users often find themselves wanting features for doing a variety of system-level tasks such as networking, file I/O, and calling out to libraries. MLud, instead of adding support for these and many more such things itself, allows you to create methods that directly include inline Standard ML, an extensive language that already has support for nearly anything one might want to do. All primitives in the standard runtime environment are implemented with this mechanism. Not only is this useful for supporting key features, but it's also useful for optimizing key portions of code for speed.
Between the language itself and the standard library, MLud includes support for all of the following datatypes:
| Type | Description |
array | A mutable array of arbitrary objects of a fixed size. A literal syntax is provided, as arrays are used in every method call. |
boolean | A simple true/false value with several boolean operations. |
char | A single character, with several testing and manipulation operations such as isAlpha. |
closure | A closure, like Lisp closures or Smalltalk blocks, representing a computation that carries some of the state of the environment in which it was created, usually by an anonymous function literal. |
integer | An arbitrary-precision integer, with arithmetic, comparative, and limited bitwise operators. |
list | A sophisticated list data structure allowing insertion or removal at both ends as well as concatenation in amortized constant time; ideal for building stacks, queues, and lists. |
map | A tree map data structure, mapping arbitrary key objects to arbitrary value objects, like a hash in Perl. A strict order of the keys is maintained. A literal syntax is provided. |
real | An IEEE floating-point type, including arithmetic and comparative operators. |
string | A string of characters, including comparison and common string-manipulation methods. |
symbol | As in Lisp, a type of string used for identification with fast comparison. |
All of the sequence objects can have operations mapped, applied, folded, or filtered over them using closure objects, allowing fast and simple ways of manipulating these containers in user code.
Most of the built-in types also support a variety of conversions,
among which are toLiteral, a method used to generate
a string describing the contents of the object for debug purposes.
Using a simple related function of Standard ML, MLud is able to save the entire state of the system to disk, so that it can be reloaded after an intentional or unintentional shutdown.
Important features MLud should have that it does not yet have include:
The ideal persistence mechanism would be much more powerful, making incremental updates to the disk at all times, as well as enabling controlled distribution of parts of the system to other MLud systems.
On a multiuser collaborative system, it's important to have security at the level of the code, so that people cannot, either intentionally or accidentally, invoke functionality that will have adverse effects on the system. Traditional image-based systems such as Smalltalk fail to address this. Currently, MLud only supports this in the form of supplying contextual information, such as the caller object, to a called method.