Next: CREATE..DOES> applications, Previous: User-defined defining words with colon definitions, Up: User-defined Defining Words
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
This fragment defines a defining word def-word and then
executes it. When def-word executes, it CREATEs a new
word name, and executes the code code1. The code code2
is not executed at this time. The word name is sometimes called a
child of def-word.
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, i.e., the address a created word returns by
default).
You can use def-word to define a set of child words that behave
similarly; they all have a common run-time behaviour determined by
code2. Typically, the code1 sequence builds a data area in the
body of the child word. The structure of the data is common to all
children of def-word, but the data values are specific – and
private – to each child word. When a child word is executed, the
address of its private data area is passed as a parameter on TOS to be
used and manipulated1 by code2.
The two fragments of code that make up the defining words act (are executed) at two completely separate times:
Another way of understanding the behaviour of def-word and
name is to say that, if you make the following definitions:
: def-word1 ( "name" -- )
CREATE code1 ;
: action1 ( ... -- ... )
code2 ;
def-word1 name1
Then using name1 action1 is equivalent to using name.
Another way of writing def-word is (see Quotations):
: def-word ( "name" -- ; name execution: ... -- ... )
create code1
[: code2 ;] set-does> ;
Gforth actually compiles the code using does> into code
equivalent to the latter code. An advantage of the set-does>
approach is that you can put other code behind it and you can use it
inside control structures without needing workarounds. A disadvantage
is that it is Gforth-specific.
A classic example is that you can define CONSTANT in this way:
: CONSTANT ( w "name" -- )
CREATE ,
DOES> ( -- w )
@ ;
or equivalently
: CONSTANT ( w "name" -- ; name execution: -- w )
create ,
['] @ set-does> ;
When you create a constant with 5 CONSTANT five, a set of
define-time actions take place; first a new word five is
created, then the value 5 is laid down in the body of five with
,. When five is executed, the address of the body is put
on the stack, and @ retrieves the value 5. The word
five has no code of its own; it simply contains a data field
and the xt of the quotation or of @.
The final example in this section is intended to remind you that space
reserved in CREATEd words is data space and therefore can be
both read and written by a Standard program2:
: foo ( "name" -- )
CREATE -1 ,
DOES> ( -- )
@ . ;
foo first-word
foo second-word
123 ' first-word >BODY !
If first-word had been a CREATEd word, we could simply
have executed it to get the address of its data field. However, since it
was defined to have DOES> actions, its execution semantics are to
perform those DOES> actions. To get the address of its data field
it's necessary to use ' to get its xt, then >BODY to
translate the xt into the address of the data field. When you execute
first-word, it will display 123. When you execute
second-word it will display -1.
In the examples 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).