July 2001
Functions
This document is intended as a primer for understanding function representation in the DBOS. It provides high-level ideas and reasons for some design issues. This document also familiarizes the reader with the nomenclature involved with functions. Implementation documentation can be found in the KMAL section of this web site.
Definition of "Function"
A "function" is an object that describes behavior on information. A "function" does not have variable or stack space, nor is it executable. The "function" name is consistent with mathematics: a definition of what to do, not the act of doing.
Functions take two forms. The first form is called a handler. Handlers are attributes of a class, and define what to do upon receiving a message. Handler instances are commonly extensions of an object. The act of extending makes the use of "this" in Object Code have dual, but unambiguous, meaning. Instructions are the second form of functions, they are not attributes of any class. Instruction instances can be summoned to do work at any time, and with respect to the execution of the application, can be global in scope.
The functionality described by a function is declared semantically by KMAL and logically by the DBOS' Messaging State Machine. KMAL is the language of the DBOS that maps text to the structures that describe a function.
Function Instances are the objects that act. How they act is defined by the Function they instantiate. Note how this relationship from definition to action is just like the Inheritance and Instantiation paper says instantiation should work. If we also consider the Primitive Attributes document, we see that functions must be classes because functions have instances.
A Function Instance is only a set of variables, and a recording of its current state. It does not contain the machine code that is executed. Technically the machine code is just another description of what is to be done, not the action of doing it. You can see that a Function instance is no more than a block of bits. For this reason, and brevity, we call a Function Instance a frame.
In most programming languages, frames are hidden from the programmer. A frame is usually the stack space needed to run the function. The model of a frame in DBOS is a little different: there is no stack.
The elimination of a stack helps with a multithreaded paradigm. A stack is intrinsically serial-process related. It is important that new languages try to remove this serial dependency; it is important that they remove the stack. Serial execution is done explicitly in other ways, using recursion, or blocking. The application programmer is kept from abusing the latent serial implications of the stack. The serial-parallel compiler must be told when serial execution is necessary, and does not have to figure out when it may be just an anomaly of stack manipulation.
Frames are Objects
This concept is quite important and be restated as "frames are closures". The implications of a frame being an object are many. In this section we will go through the various properties of objects and how they relate when we speak specifically of a frame.
A frame is an object. The frame contains all the space for any variables the function might refer to. Just like objects, frames have a finite number of variables. Raw heap and stack space are accessible to a frame only through other objects. All the resources of the DBOS are at a frame's command, limited only by security.
The use of frames replaces the traditional stack, and this has useful advantages. The variables in a frame can be set before "execution". This allows a user to have one function describe a variety of functionality that differs only by a few constants. For example, a function that compares a string to some constant string. The constant string can be set in a frame at the start of the application, and the frame executed with only a single parameter. Other threads can make copies of this frame to run many compares at a time.
Frames are able to send messages. This ability has a parallel in standard languages: throwing exceptions, and returning values. Technically a frame has no return values, it just stops execution, and removes itself from existence. Results have to be returned in messages sent back to the caller1. KMAL design realizes that this extra message passing is unnecessarily complicated. The semantics of the return is just like that of a function call. It is the compiler that sets up the messaging. The ability to message a result from a function allows any result to be returned, including exceptions.
Frames can receive messages. The messages received either come directly from the callee (as a return value or exception) or as a regular message. A callee message is placed at the front of the frame's message queue so that it will be consumed next. Notice that exception handling turns out to be elegant when treated as just another type of return message. When a regular message is sent to an object it is merely redirected to the appropriate frame for execution and is placed at the end of the frame's message queue. .
A truly good piece of software needs to manage the exceptions that might arise, but doing so reduces the readability of the code. Exception Handlers are functions that listen to executing function instances. These handlers can be separated from the main code and managed separately2. If you inspect the JVM class file format5, you will see Sun's attempt at creating this separation between the function and its exception handlers.
Sending Messages
Sending a message is a recursive exercise. To send a message it has to be created, populated with values and transmitted by the executing frame. All these operations require instructions to run, and messages to be sent. Therefore, without a base case, no work can be done. This self-referencial dependency is removed by making instruction execution an atomic process. This means that the assigning of values to the variables in a new message are done implicitly and are part of the instruction executed. This is quite sensible because the compiler will not be making code that uses messaging anyway. Each transition in the MSM will relate every parameter for its message with the frame variable that the parameter will get its value from. Adding this base functionality does not preclude the user from still constructing messages explicitly. Explicit message construction is still available when required.
The Function Type
The Function Type object is important; it is the embodiment of the Function Type Attribute. This object represents the process of turning functional description into action. Any instance of the Function Type will be a function. Since functions are classes, we see that the Function Type is a special in that it is a Class Class.
Jan 2000, initial writing
July 2001, update