It has it inside out.
: CONSTANT CREATE , DOES> @ ;
CREATE makes a header, then its data is filled, then it is bestowed with some action.
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.
: 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. It is also in contrast with the oo en vogue, in that there is no distinction between data and methods. A smart field is just some action working on an offset in a data structure.
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 AK ward, 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.
At first I used still the old syntax as follows
struct aap :F REAL-PART , DOES> @ ; :F IMAGINARY-PART , DOES> @ ; endstruct
It may be less neat but functionally equivalent, but the interesting point is that structures in Forth automatically 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
COMPLEX Z Z . .
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. 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.
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 ;
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 is yet unclear or maybe we need a ; here.)
Washer exampleThe 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 4.x.x. For newer versions of ciforth you may need to preceed it withWANT -legacy-