3.31 Defining Words

:, create, and variable are definition words: They define other words. Constant is another definition word:

5 constant foo
foo .

You can also use the prefixes 2 (double-cell) and f (floating point) with variable and constant.

You can also define your own defining words. E.g.:

: variable ( "name" -- )
  create 0 , ;

You can also define defining words that create words that do something other than just producing their address:

: constant ( n "name" -- )
  create ,
does> ( -- n )
  ( addr ) @ ;

5 constant foo
foo .

The definition of constant above ends at the does>; i.e., does> replaces ;, but it also does something else: It changes the last defined word such that it pushes the address of the body of the word and then performs the code after the does> whenever it is called.

In the example above, constant uses , to store 5 into the body of foo. When foo executes, it pushes the address of the body onto the stack, then (in the code after the does>) fetches the 5 from there.

The stack comment near the does> reflects the stack effect of the defined word, not the stack effect of the code after the does> (the difference is that the code expects the address of the body that the stack comment does not show).

You can use these definition words to do factoring in cases that involve (other) definition words. E.g., a field offset is always added to an address. Instead of defining

2 cells constant offset-field1

and using this like

( addr ) offset-field1 +

you can define a definition word

: simple-field ( n "name" -- )
  create ,
does> ( n1 -- n1+n )
  ( addr ) @ + ;

Definition and use of field offsets now look like this:

2 cells simple-field field1
create mystruct 4 cells allot
mystruct .s field1 .s drop

If you want to do something with the word without performing the code after the does>, you can access the body of a created word with >body ( xt -- addr ):

: value ( n "name" -- )
  create ,
does> ( -- n1 )
  @ ;
: to ( n "name" -- )
  ' >body ! ;

5 value foo
foo .
7 to foo
foo .

Assignment: Define defer ( "name" -- ), which creates a word that stores an XT (at the start the XT of abort), and upon execution executes the XT. Define is ( xt "name" -- ) that stores xt into name, a word defined with defer. Indirect recursion is one application of defer.

Reference: User-defined Defining Words.