Last updated: 15 November 2010


SWOOP



Contact


Leon Wagner

Download


The file swoop.zip includes compatibility layers for SwiftForth and VFX Forth.


Introduction


This OOP package is called SWOOP (Swift Object-Oriented Programming). It includes all the essential features of object-oriented programming, including:

  • Encapsulation: combining data and methods into a single package that responds to messages.
  • Information hiding: the ability of an object to possess data and methods that are not accessible outside its class.
  • Inheritance: the ability to define a new class based on a previously defined ("parent") class. The new class automatically possesses all members of the parent; it may add to or replace these members, or define behaviors for deferred members.
  • Polymorphism: the ability of different sub-classes of a class to respond to the same message in different ways. For example, all vehicles can steer, but bicycles do it differently from automobiles.

Basic Components


This section will present a simple example of a class for the purpose of discussing its members, an instantiation of the class, and its use. This example will be extended in various ways in subsequent sections.


A Simple Example

POINT (defined below) is a simple class we shall use as a primary building-block example for SWOOP. It demonstrates two of the four basic class member types: data and colon.

The word following CLASS is the name of the class; all definitions between CLASS and END-CLASS belong to it. These definitions are referred to as the members of the class. When a class name is executed, it leaves its handle (xt) on the stack. The constructor words are the primary consumers of this handle.

CLASS POINT
VARIABLE X
VARIABLE Y
: SHOW ( -- )   X @ . Y @ . ;
: DOT ( -- )   ." Point at " SHOW ;
END-CLASS

The class definition itself does not allocate any instance storage; it only records how much storage is required for each instance of the class. VARIABLE reserves a cell of space and associates it with a member name.

The colon members SHOW and DOT are like normal Forth colon definitions, but are only valid in the execution context of an object of type POINT. X and Y also behave exactly like normal Forth VARIABLEs.

There are five kinds of members:

  • Data members include all data definitions. Available data- member-defining words include CREATE (normally followed by data compiled with , or C,), BUFFER: (an array whose length is specified in address units), VARIABLE, CVARIABLE (single char), or CONSTANTs.
  • Colon members are definitions that may act on or use data members.
  • Other previously defined objects, available within this object.
  • Deferred members are colon-like definitions with default behaviors that can be referenced while defining the class, but which may have substitute behaviors defined by sub-classes defined later. These allow for polymorphism and late binding.
  • Messages are un-named responses to arbitrary numeric message values (such as Windows messages).

CLASS ( -- )
Begin a class definition that will be terminated by END-CLASS. All definitions between CLASS and END-CLASS are members of the class name. Invoking name returns the handle (xt) of this class.

END-CLASS ( -- )
End a class definition.

Static Instances of a Class

Having defined a class, we can create an instance of it. BUILDS is the static instance constructor in SWOOP; it is a Forth defining word and requires the handle of a class on the stack when executed. For example:
POINT BUILDS ORIGIN
.. defines an object named ORIGIN that is a static instance of the POINT class. Now, any members of POINT (e.g., the X and Y variables defined in the earlier example) may be referenced in the context of ORIGIN. For example:

5 ORIGIN X !
8 ORIGIN Y !
ORIGIN DOT

X and Y are data members of ORIGIN that were inherited from POINT and the values stored into them here are completely independent of the X and Y members of any other instances of the POINT class. X and Y have no existence independent of an instance of POINT.

DOT is a colon member of the POINT class. When it executes in the context of a specific instance of POINT such as ORIGIN, it will use the addresses for the versions of X and Y belonging to ORIGIN.

When the name of an object is executed, two things happen: first, the Forth interpreter's context is modified to include the namespace of the class that created it. Second, the address of the object is placed on the stack. The phrase:

ORIGIN 2 CELLS DUMP

.. is perfectly valid. Each of the members of the class act on this address: members that represent data simply add an offset to it; members that are defer or colon definitions push the address into 'SELF which holds the current object address before executing, and restore it afterwards.

You can build an array of objects of the same class using BUILDS[]. Individual instances of such an array must be provided with an index. For example:

20 POINT BUILDS[] ICOSOHEDRON[]
0 ICOSOHEDRON[] DOT
1 ICOSOHEDRON[] DOT
...
19 ICOSOHEDRON[] DOT

The [] in the name is used as a reminder that this is an array.

Dynamic Objects

We can also create a temporary context in which to reference the members of a class. NEW is a dynamic constructor that will build a temporary instance of a class; it is not a defining word, but is a memory management word similar to ALLOCATE. It requires a class handle on the stack, and returns an address. When the object is no longer needed, it can be disposed of with DESTROY.

USING parses the word following it, and (assuming that it is the name of a class) makes its members available for use on data at a specified address. For example:

0 VALUE FOO            \ Contains pointer to instance
POINT NEW TO FOO       \ Construct instance of class POINT
8 FOO USING POINT X !  \ Store data in X
99 FOO USING POINT Y ! \ Store data in Y
FOO USING POINT DOT    \ Display X and Y
FOO DESTROY  0 TO FOO  \ Release space

This example uses FOO to hold the address of an instance of POINT. After the instance is created, it may be manipulated (with a slight change in syntax) in the same way that a static instance of POINT is. When it is no longer needed, the instance is destroyed, and the address kept in FOO invalidated.

A somewhat cleaner means of invoking a member of a dynamically instantiated object uses the word CALLING or its synonym ->, with the following syntax:

 CALLING    or
 -> 

Use of the object name provides the address of its data structure, to which the member's function will be applied. This differs from the more generic USING, because it will ensure that the member is actually part of the object's namespace, whereas USING applies an arbitrary member function to an arbitrary address. Objects constructed by NEW do not exist in the Forth dictionary, and must be explicitly destroyed when no longer used.