Forth lecture 15.

Structures and classes in Forth.

The disadvantages of the old stuff.

BUILDS DOES was one of the first object oriented stuff ever (pre 1975).

It has it inside out. Nowaday it is followed up by:

: CONSTANT CREATE , DOES> @ ;

CREATE makes a header, then its data is filled, then it is bestowed with some action.

Fundamental problems:

All structs defined in Forth copy object oriented concepts in an unForthy way, because they make a distinction between data (fields) and methods (code). But of course a field is merely a method that puts an address on the stack. We will see that it is the default action, comparable to a

 DOES>
that is followed immediately by a semicolon.

The correct approach.

If we turn

: CONSTANT CREATE , DOES> @ ;

inside out we get the more correct


0 \ Sample input.
CLASS CONSTANT
M: CONTENT @ M;   ,
ENDCLASS

This generalizes to

0 0 \ real, imaginary
class COMPLEX
M: REAL-PART @ M;        ,
M: IMAGINARY-PART @ M;   ,
endclass

This is in contrast with the CREATE DOES construct that doesn't bear generalizing. Methods work on an offset in the current data structure, not just at offset zero. It is also in contrast with the oo en vogue, in that there is no distinction between data and methods. A field is just some method giving back an offset in a data structure, without performing an action. The usage of COMPLEX is

1 2 COMPLEX Z
Z REAL-PART .   Z IMAGINARY-PART .

So Z makes this the current object (by filling in a pointer ^COMPLEX) and REAL-PART adds a known offset to this pointer, then does its thing. The second Z can be left out.

The definition of Z requires some class dependent data, in this case 1 and 2. The data to build the data structure is to be supplied during the definition of the class too. This is such that a trial build can take place and the offsets of the fields can be determined.

At first sight it may seem that the requirement to make objects current is akward, but in practice it isn't too bad. I can testify that this is a viable and productive way to handle structures. It was very successful in my rewrite of the manx package. It was also instrumental in my ciasdis project.
In porting a lisp compiler it became clear that it is also useful to have a method that applies the offset to an object whose address is on the stack. This is also useful for anonymous objects.

M:r ... M;

M:...M;

you arrive at the allocation code of the data object. Structures in Forth are obsolete and become classes.

BUILDS DOES>

had the useful property that because there was just one method there was no need to specify the smart field.

In order to have this we could have a M:DEFAULT

This generalizes to

CLASS COMPLEX
M:DEFAULT 2@ ;        2,
ENDCLASS

Usage

The default field is automatically executed when the object is used. This makes it however impossible to not have that action, if you only need some other method of the class. Experience has shown that it was more convenient to use

CREATE DOES

in these case, see for example ciasdis. I am somehow convinced that using colors in color Forth works out very pleasantly, because the same word can have more than one action depending on its color.

Implementation notes.

In the implementation I have currently, a dummy object of the class is build once during compilation, and during that building the offsets are collected. This means that words like the comma in the above example are executed as well as compiled. For this purpose some code is temporarily stored in strings. This sound horrendous. However the whole class facility costs two screens, not bad for ISO Forth. This system implies that the offsets must be fixed, with the possible exception of the last field. For reference they follow in the next section.

Reference ISO implementation

This is the implementation of class endclass. It is still mimics the CREATE DOES< construction. My ministring package is of the essential.

( M: auxiliary_for_class ) \ AH A4nov26
WANT SWAP-DP
CREATE NAME$ 128  ALLOT         \ The name of the struct.
CREATE CRS$ 4096 ALLOT          \ Evaluate buffer, general.
VARIABLE LAST-IN                \ Start of interpreted code
VARIABLE DP-MARKER              \ Start of alternative dict.
: !IN   IN @ LAST-IN ! ;        \ Remember last value of ``IN''
: IN$  LAST-IN @ IN @  OVER - ; \ Return input STRING since !IN
: itoa   0 <# #S #> ;           \ Transform an INT to a STRING.
\ Compile "method" working on addres with offset.
    CREATE M$ 256 ALLOT         \ Evaluate buffer, method.
: M:   IN$ 3 - CRS$ $+!   "^" M$ $!   NAME$ $@ M$ $+!
   " @ " M$ $+!   HERE DP-MARKER @ - itoa M$ $+!   " +" M$ $+!
   SWAP-DP   :   M$ $@ EVALUATE ;
\ End compiling a method.
: M;   POSTPONE ;   SWAP-DP   !IN ; IMMEDIATE
( class endclass ) \ AH A4jun16
WANT M:
: +NAME    NAME$ $@ CRS$ $+! ;  \ Add the name.
: +NAME+$   +NAME   CRS$ $+! ;  \ Add the name and a STRING.

\ Define class "name". Compile this-pointer, start build-word.
: class   NAME NAME$ $!   "VARIABLE ^" CRS$ $!
   +NAME   CRS$ $@ EVALUATE   ": BUILD-" CRS$ $!
   " HERE >R " +NAME+$   SWAP-DP   HERE DP-MARKER !   !IN ;

\ Recover memory, compile build-word and class-word.
: endclass   ?EXEC   DP-MARKER @ HERE - ALLOT   SWAP-DP
   IN$ 9 - CRS$ $+!   " R> ;" CRS$ $+!   CRS$ $@ EVALUATE
   ": " CRS$ $!   " CREATE BUILD-" +NAME+$   " ^" +NAME+$
   " ! DOES> ^" +NAME+$   " ! ;" +NAME+$   CRS$ $@ EVALUATE ;


The version in modern versions of ciforth rely on FORMAT&EVALUATE that results in cleaner code. For colorforth we would have to use two new colors probably. A new color is needed be for defining a class, the red, yellow and green colors are for defining, execution and compilation of fields and a separate color again for the default action.

This is how it would look:

<orange>COMPLEX   ( a class)
<red>REAL-PART <yellow>@        <green>,
<red>IMAGINARY-PART <yellow>@   <green>,

The red color is used with a class name to define a word from that class. ( How to end a class in colorforth is yet unclear; maybe we need a ; here.)

Washer example

The washer example is famous for it supposedly demonstrates that good Forth code needs no comment. It show how to program a washing machine. This is an object oriented version of the code for lina or wina version 5.x.x.

  • Other Forth lectures
  • Go to the home page of Albert van der Horst