Objects in Holon

Wolf Wejgaard

Presented at the EuroFORTH conference 1997


Objects are desirable program elements. Holon, an interactive Forth cross-platform development system, contains an object type mechanism for the definition of objects in embedded systems. HolonForth dispenses with the complexity of a class hierarchy and implements early binding. The methods are global words that are bound to private messages in an object type. Thus methods can be inherited. A default method applies, when an object is used without a message. The compiler checks for the validity of messages. Holon also offers a mechanism for the definition of arrays in algebraic notation, e.g. MATRIX( J K ).

1. Objects

Objects are data structures with private access functions (methods) that are invoked by sending a message to the object. Objects make programs easier to read and better to handle. Objects are created by defining words that are called classes. Forth provides a mechanism for building defining words, therefore classes are easily implemented in Forth. 

Conventional object-oriented systems hide methods inside classes. Thus a method can only be called inside the defining class and cannot be reused in another class. In order to reuse the code, an inheritance mechanism has been invented. Classes are derived from other classes. The new class uses the existing methods and data structures and adds its own elements. Sometimes the new class redefines an existing method, in order to reuse the method's name. This allows operator overloading and polymorphism.

An object-oriented programming system usually contains many classes that are bound in a class hierarchy. The class hierarchy brings order to programs. Every element has its place in the hierarchy. Many programmers and particularly their managers love order and favor object-oriented programming systems. The hierarchy may be useful for program libraries. But there are better ways to order a program.

Objects are also used in Forth systems. Many object-oriented implementations are available [1]. The syntax for the definition of a class typically looks like Figure 1. The data elements and the methods are defined inside the definition of the class. The compiler creates a private list (table or vocabulary) for the names of the variables and methods.

2. Holon

Holon is an interactive integrated cross-platform development system based on Forth [2]. The main difference to a conventional Forth system is the management of the source text in a database; every program word has a record in the database. The word orientation provides for new features in Forth programming.

Holon orders the words in a structure of modules and groups and makes the program readable like a book. Holon lets you work as directly on a target program as you are used to work on a text in your text editor. Every change is immediately effective; the changed words are reloaded and the code is substituted in the running target program. Holon generates only the target code that is actually used. If you load a word, all sub words that are called by this word are also loaded. And there is more.

However, you can not compile the class syntax of Figure 1. Holon does not allow the definition of other words inside a word definition. 

Class Point super Object
    int X
    int Y
    m: get ( -- x y ) ... ;m
    m: put ( x y -- ) ... ;m
    m: move ( dx dy -- ) ... ;m

Figure 1: Typical syntax for the definition of a class


3. Object types

Holon uses objects extensively; every system variable is an object. But Holon does not implement a class structure. There is no inheritance of classes, yet all methods can be reused. Figure 2 shows the definition of classes in Holon. 

The behavior of an object is defined in one place. You don't have to look for details along an inheritance chain. 

: GetPoint  ( obj -- x y )  2@  ;
: PutPoint  ( x y obj -- )  2!  ;
: MovePoint  ( dx dy obj -- ) 2+!  ;
 Message: get
 Message: put
 Message: move
ObjectType: Point
      Data: , ,
   Methods: GetPoint PutPoint MovePoint
  Messages: get      put      move 

Figure 2: The definition of a class in Holon

The object syntax of Holon is based on the work of Terry Rayburn [3]. It uses the CREATE-DOES> construct and has the DOES> part embrace a collection of methods. I have extended the method to the meta-compiler mechanism of Holon.

Object type: Every object type is autonomous, it is not derived (inherited) from another type. Therefore I do not call it a class. I want to avoid the notion of a hierarchical class structure.

Data: This word is equivalent to CREATE. The data space is built by words like INTEGER, and BYTE, . These words replace the archaic "," and "C,". Holon does not use named instance variables. It is rarely a problem to work on the data structure directly, at least in the realms of embedded systems.

Methods: The methods are predefined global words. They are easy to look up and test, and they can be reused in other object types.

Messages: Messages are also global words that can be reused. The messages GET and PUT probably already exist due to the definition of the basic object types of your system. Holon discriminates between method and message. The methods are bound to an object together with the message that calls the method. Since a message can be paired with different methods, we have polymorphism and can overload operators.

4. Implementation

Holon is a cross-compiler. The object type mechanism works in the host and creates code in the target. The methods are defined in the target, and the data space is built in the target, whenever an object is created. Objects are created at compile time, and messages are linked at compile time (early binding). This is no restriction for closed embedded systems.

The definition of an object type (Figure 2) creates a structure in the host, which contains:

1. The code that generates the data space in the object. This code normally consists of host words, but it may call target words as well. Holon operates on a living target system during program development. Thus target words can be executed while the program is loaded. This allows the creation of high level Forth constructs in cross-platform programming.

2. An array of methods. The array contains the execution tokens of the methods.

3. An array of messages. A message is characterized by a unique number. In a conventional system you might use a hash code. In Holon every word already has a unique number: its index in the database.

5. Mechanism

In Holon the messages are applied to objects (prefix notation, e.g. ... move ThePoint ...) The message is an immediate word that stores the associated number in a system variable MSG#. The object then fetches the MSG#, and looks for the message in its table. If the message does not exist for this object, Holon indicates an error, otherwise the object fetches the corresponding method from the methods table.

If the object is called in interpreting mode, it puts the address of its data space on the stack and executes the method. In compiling mode the object compiles the execution token of a code routine, which delivers the address of the data space at runtime, followed by the execution token of the method. Thus the invocation of an object compiles to two cells.

The mechanism provides for a default method. If an object is used without a message, the system variable MSG# contains 0. The object then uses the first method in the list. In an Integer object the first method is GetInteger, therefore the Integer delivers its value, as we would expect it to do.

6. Arrays

Arrays have been a problem in Forth. How do we pass array indices in addition to the operator and the parameters? This is one case where the algebraic notation ARRAY( I J ) seems more appropriate. Fortunately, the object mechanism of Holon can be extended to make this notation possible. The solution is to delay the object.

A delayed object neither interprets nor compiles but pushes the message number and the code address of the object's action on an object stack. The indices are then pushed on the data stack by the program. Finally the closing parenthesis ")" pulls the message number and object address from the object stack and asks the object to do its business.

The indices can also be objects. You can write ARRAY( X Y ), where X and Y are integer objects. Holon nests objects inside delayed objects. The closing parenthesis ")" is independent of the type of the object. The object knows its own type and acts accordingly. I.e. there is no need to use different types of closing parameters ")" ,"))", ")))" etc. for different array dimensions.

7. Conclusion

Holon provides objects for embedded systems. There is no class hierarchy and the mechanism is simple and reliable. Methods are defined as global Forth words and therefore can be reused (inherited). Holon separates methods from messages and allows overloading and polymorphism without class inheritance.

8. References

[1] E.g. Andrew McKewan, Object-Oriented Programming in ANS Forth, Forth Dimensions, XVIII,6 (March 1997), p.14-29

[2] Wolf Wejgaard, Holon - A New Way of Forth, Proc. EuroFORTH, 1992, p. 13-18

[3] Terry Rayburn, METHODS> Object-Oriented extensions redux, FORML Proceedings, 1987, page 343-355