It has it inside out.
: 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.
: 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
Usage
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 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 4.x.x.
For newer versions of ciforth
you may need to preceed it with
   WANT -legacy-