Previous Next Contents

6. Base Types

Data held in the ColdStore are typed, and stored in the form of one of a number of Base Types (the set of which is extensible) which are held in Modules, obey the Virtual Protocol, can be Identified and are associated with a ColdStore Object which is their Type Manager.

6.1 Slot

The Slot C++ class is a smart-pointer class which performs several functions:

6.2 ColdStore Modules

ColdStore's exectuable components are presented as dynamically linkable objects in a directory, and are loaded by the server ab initio (in the case of certain fundamental services), or on demand, in the case of user-defined modules.

Coldmud's Base types are defined in terms of C++ objects (via the Virtual Protocol) and their associated C++ methods which are stored and loaded via their defining Module.

Modules may only be explicitly loaded by the System Object (see Security), and then only via a Builtin.

Modules are visible within ColdStore scope, as a kind of Builtin. The `defining Module' component is the String name of the BaseType exported by this Module, the `function name' component is a String representing the Unix file-name of the relocatable object module to dynamically load and link.

Clearly, access to Modules before the Module Module has been linked in is likely to cause problems, but this loading occurs early in the bootstrap procedure.

Module's [] operator can only be called by the System Object, and treats a String argument as the name of a C++ symbol to be looked up in the Module. In resolving a C++ symbol, the glyph `%s' is substituted by the name of the C++ class exported by the Module, and `%d' is substituted by the length of this name. The result of this lookup is either an error  dictnf, or a Builtin instance.

Multiple Modules may reference the same relocatable object, each such object is loaded only once.

The functionality of Module is largely provided by Linux's libdl.so (version 1.9.6, at time of writing.)

6.3 Type Identification

ColdStore uses C++'s RTTI to derive a name of each instance, and maps this to a `managing type' for each object.

The C-- compiler understands the .type() method to always refer to this Builtin.

6.4 Type Managers

The Managing Type of an object is a Named Object which contains methods defining the functionality of the type.

The Managing Type's name is the same as that of the C++ type which implements it. Managing types are created by the Module subsystem when it loads a Module.

6.5 Constructors

Constructors are invoked on basetypes by calling the object as if it were a Method. This is syntactic sugar for $basetype.basetype(args...), generalised from classic Coldmud's Buffer constructor.

So, to construct a List, one could use $List(elements ...), assuming List's Type Manager to be List.

6.6 Data and Container Base Types

Integers

Integers are omnipresent, and it makes sense to give them special treatment.

The Integer object is a fairly straight-forward subtype of Data, but Slot takes special cognisance of it: A Slot whose low order bit is 1 represents an encoded 31 bit signed int.

Slot must test this condition on each dereference, and act as an identity function for encoded integers.

In the case that an operation from the Virtual Protocol is being performed, Slot must construct a heavyweight Integer object from the lightweight encoded form (coercion), manipulate this object, and re-encode the result (if the result fits into 30 bits + sign bit).

Integer will have a refcount, but the refcount need never be more than 1 (I think.)

Integer may be a multiprecision integer from one of the many packages, or there may be AKO integer which contains one of these.

There may be a pool of Integers from which to draw heavyweight Integers.

Strings

Lists

Tuples

Dicts

Orders

Iterators

Connections

6.7 Synthetic Base Types

Symbols

Errors

An Error object is a 4Tuple containing the following:

Errors compare by Error Type alone, so two errors with different Values and Explanations will be considered identical by the Order Virtual Protocol element.

Objects

Methods

Tasks

Tasks contain kinds of Lists with the following additional property: the domain of indices used to access their contents may be constrained by means of Frame operators to a subrange of their length, and all indices are interpreted relative to the current start of Frame.

Tasks include the following components:

Stacks

Stacks are components of Tasks, in C--, and not distinct entities.

They are implemented as a kind of List with the additional property that they may be constrained to be relatively addressable, in order to prevent some Builtin or Virtual Protocol element from running amok with the stack.

Note, however, that it is the responsibility of the Concrete Protocol referenced by an Interpreter to enforce stack constraint. The implementor may decide to trust Virtual Protocols to behave well, for efficiency.

When the C-- compiler sees a reference to a method-local variable, it translates this to a lookup in the current stack using the [] operator having pushed the Integer index of the referenced variable.

Frames

Frames are used to delimit subranges of the stack component of a Task when they pushed onto the Stack.

Exception handling, statement grouping, argument grouping, iterative constructs are styled as Frame operations in C--.

Builtins

Builtins provide a conventional means of access by ColdStore Interpreters to functions defined by the underlying C++ implementation. They need to be distinct types, because they myst be dynamically linked when the Module which contains them is invoked.

The Builtin type responds to the Call Virtual Protocol element by constraining the Stack to the current Frame and calling the C++ function.

Builtins must be Interned, so that all references to a Builtin may be linked in one operation.

Builtins present to ColdStore Interpreters as a 2Tuple of:

Builtins have another field, inaccessible to ColdStore Interpreters, containing a pointer to a function of a single argument of type Error &* returning Slot.

A Builtin throws an error by assigning an Error Object to the reference argument, and returning a value which will be discarded ( (Data*)0 serves the purpose admirably.)

Arguments to Builtins must be picked off the current Stack by the builtin's C++ code. Access to the stack is severely constrained by the Call operator defined by the C-- Concrete Protocol, which ensures that the only stack contents visible to the Builtin are those of the current Frame.

Interpreters are Tuples containing Builtins.

Compilers

C-- Compiler

Interpreters

Iterators are an object which exists purely to traverse Sequence and Map types. An operator to return an iterator for a given object is defined in the Sequence Protocol of the Virtual Protocol.

Iterators are required to respond to the truth and positive virtuals, for testing completion, and returning the next iterated value, respectively.


Previous Next Contents