Go to the first, previous, next, last section, table of contents.


User-defined Defining Words

You can create new defining words simply by wrapping defining-time code around existing defining words and putting the sequence in a colon definition.

If you want the words defined with your defining words to behave differently from words defined with standard defining words, you can write your defining word like this:

: def-word ( "name" -- )
    Create code1
DOES> ( ... -- ... )
    code2 ;

def-word name

Technically, this fragment defines a defining word def-word, and a word name; when you execute name, the address of the body of name is put on the data stack and code2 is executed (the address of the body of name is the address HERE returns immediately after the CREATE).

In other words, if you make the following definitions:

: def-word1 ( "name" -- )
    Create code1 ;

: action1 ( ... -- ... )
    code2 ;

def-word name1

Using name1 action1 is equivalent to using name.

E.g., you can implement Constant in this way:

: constant ( w "name" -- )
    create ,
DOES> ( -- w )
    @ ;

When you create a constant with 5 constant five, first a new word five is created, then the value 5 is laid down in the body of five with ,. When five is invoked, the address of the body is put on the stack, and @ retrieves the value 5.

In the example above the stack comment after the DOES> specifies the stack effect of the defined words, not the stack effect of the following code (the following code expects the address of the body on the top of stack, which is not reflected in the stack comment). This is the convention that I use and recommend (it clashes a bit with using locals declarations for stack effect specification, though).

Applications of CREATE..DOES>

You may wonder how to use this feature. Here are some usage patterns:

When you see a sequence of code occurring several times, and you can identify a meaning, you will factor it out as a colon definition. When you see similar colon definitions, you can factor them using CREATE..DOES>. E.g., an assembler usually defines several words that look very similar:

: ori, ( reg-target reg-source n -- )
    0 asm-reg-reg-imm ;
: andi, ( reg-target reg-source n -- )
    1 asm-reg-reg-imm ;

This could be factored with:

: reg-reg-imm ( op-code -- )
    create ,
DOES> ( reg-target reg-source n -- )
    @ asm-reg-reg-imm ;

0 reg-reg-imm ori,
1 reg-reg-imm andi,

Another view of CREATE..DOES> is to consider it as a crude way to supply a part of the parameters for a word (known as currying in the functional language community). E.g., + needs two parameters. Creating versions of + with one parameter fixed can be done like this:

: curry+ ( n1 -- )
    create ,
DOES> ( n2 -- n1+n2 )
    @ + ;

 3 curry+ 3+
-2 curry+ 2-

The gory details of CREATE..DOES>

DOES>       compilation colon-sys1 -- colon-sys2 ; run-time nest-sys --         core       ``does''

This means that you need not use CREATE and DOES> in the same definition; E.g., you can put the DOES>-part in a separate definition. This allows us to, e.g., select among different DOES>-parts:

: does1 
DOES> ( ... -- ... )
    ... ;

: does2
DOES> ( ... -- ... )
    ... ;

: def-word ( ... -- ... )
    create ...
    IF
       does1
    ELSE
       does2
    ENDIF ;

In a standard program you can apply a DOES>-part only if the last word was defined with CREATE. In Gforth, the DOES>-part will override the behaviour of the last word defined in any case. In a standard program, you can use DOES> only in a colon definition. In Gforth, you can also use it in interpretation state, in a kind of one-shot mode:

CREATE name ( ... -- ... )
  initialization
DOES>
  code ;

This is equivalent to the standard

:noname
DOES>
    code ;
CREATE name EXECUTE ( ... -- ... )
    initialization

You can get the address of the body of a word with

>body       xt -- a-addr       core       ``to-body''


Go to the first, previous, next, last section, table of contents.