Skip to main content

Words

A word is an identifier for an execution token, also known as a WordDef. To define a new word, first define a WordDef by enclosing code inside { }; then invoke word : followed by the identifier for the word. For instance,
// square takes the square of the integer at the top of the stack
{ dup * } : square
defines a new word square, which executes dup and * when invoked. Typing 5 square becomes equivalent to typing 5 dup *, and produces the same result:
5 square   // Produces 25 at the top of the stack
5 dup *    // Produces 25 at the top of the stack
It is possible to use the new word inside new word definitions:
// **5 raises the integer at the top of the stack to the 5th power
{ dup square square * } : **5
3 **5   // Produces 243 at the top of the stack.
If the word indicated after : is already defined, it is redefined. However, all existing definitions of other words will continue to use the old definition of the redefined word. For instance, if square is redefined after the definition of **5 above, **5 will continue to use the original definition of square.

Constants

A constant is a word that pushes a predefined value when invoked. Constants can defined using the word constant. For instance,
1000000000 constant Gram
defines a constant Gram equal to 10^9. In other words, 1000000000 will be pushed into the stack whenever Gram is invoked:
// Pushes Gram and 2 into the stack.
// Then, multiplies them, producing 
// 2000000000 at the top of the stack.
Gram 2 *   
Of course, it is possible to use the result of a computation to initialize the value of a constant:
// Define constant mGram with the result 
// of the computation Gram 1000 /
Gram 1000 / constant mGram
mGram    // Pushes 1000000 into the stack
The value of a constant does not necessarily have to be an Integer. For instance, a string constant can be defined in the same way:
"Hello, world!" constant hello
hello   // Pushes "Hello, world!" into the stack
If a constant is redefined, all existing definitions of other words will continue to use the old value of the constant. In this respect, a constant does not behave as a global variable.
It is possible to store two values into one “double” constant by using the word 2constant. For instance:
355 113 2constant pifrac
defines a new word pifrac, which will push 355 and 113 (in that order) when invoked. The two components of a double constant can be of different types. If a constant with a fixed name within a block or a colon definition is needed, use =: and 2=:, instead of constant and 2constant. The word =: <identifier> takes the value at the top of stack, creates constant <identifier> and assigns the value to <identifier>. Similarly, word 2=: <identifier> takes the two top-most values in the stack, creates constant <identifier> and assigns the values to <identifier>. For instance, the following defines a word setxy, which sets constants x and y:
{ dup =: x dup * =: y } : setxy
3 setxy x y +   // Produces 12 at the top of the stack 
7 setxy x y +   // Produces 56 at the top of the stack
The code 3 setxy x y +, which is equivalent to 3 dup =: x dup * =: y x y +, changes the stack as follows:
3        // Stack: 3
dup      // Stack: 3 3
=: x     // Stack: 3    (x is 3)
dup      // Stack: 3 3
*        // Stack: 9
=: y     // Stack:      (y is 9)
x        // Stack: 3
y        // Stack: 3 9 
+        // Stack: 12
The code 7 setxy x y + has a similar explanation. To recover the execution-time value of a constant inside a block definition, prefix the constant name with the word @'. For instance, using the definition of setxy as above, the following code defines a new word addxy which accesses the constants x and y and adds them:
{ @' x @' y + } : addxy
3 setxy addxy    // Produces 12 at the top of the stack 
The code 3 setxy addxy has the same effect as the code 3 setxy x y +. The main difference between 3 setxy addxy and 3 setxy x y + is that in 3 setxy addxy, constants x and y are accessed inside a code block definition, which require the use of word @' to access them; while in 3 setxy x y +, the constants are accessed outside a code block definition, which does not require the use of word @' to access them. The drawback of this approach is that @' has to look up the current definition of constants x and y in the dictionary each time addxy is executed. Variables provide a more efficient way to achieve similar results.

Variables

Variables are a much more efficient way to represent changeable values. To declare a variable, use the word variable followed by the identifier. Internally, the word variable creates an empty box, which can then be updated with word !, and read with word @. For instance:
// Create two variables x and y, initialized to null
variable x variable y
// Set the value of x to 2
2 x !
// Set the value of y to 10
10 y !
// Read x and place the value at the top of the stack 
x @ 
// Read y and place the value at the top of the stack 
y @ 
// Add the two values
+     // Produces 12 at the top of the stack
The word variable produces variables initialized to null. Instead, to create initialized variables to a specific value, use the phrase box constant:
// Creates variable x and initializes it with value 17
17 box constant x
// Read x and place the value at the top of the stack
x @      // 17 at the top of the stack
// Increase 17 by 1
1 +
// Update x, now storing 18
x !
It is possible to define a special word for creating variables, if they are needed often:
{ box constant } : init-variable
// Create a variable x, initialized to 17
17 init-variable x
// Create a variable y, initialized to "test"
"test" init-variable y
Variables have one disadvantage compared to constants: accessing the value stored in a variable requires the use of word @. This can be mitigated by defining a “getter” and a “setter” word for a variable, and use these words to write better-looking code:
// First, create the box storing the variable contents
variable x-box

// Define word x so that it is the procedure that 
// reads the box contents.
// So, that now, x can be treated as if 
// it was the "variable".
// Instead of writing "x-box @" 
// to read the variable contents, simply write "x".
{ x-box @ } : x

// Define a similar procedure for updating variables x.
{ x-box ! } : x!

// Update variable with 5
5 x!

// Read the variable twice and add the results
x x +    // Produces 10 at the top of the stack
It is possible to define “getters” and “setters” for variables in a more generic way. The following code defines the word variable-get-set, which creates a fresh variable and takes the two strings following variable-get-set to name the variable’s getter and setter, respectively. For example, variable-get-set x x! will create a variable with getter x and setter x!.
{ hole dup 1 ' @ does create 1 ' ! does create } : variable-get-set
Word variable-get-set works as follows:
// Create a fresh box containing null
hole     // Stack: Box
// Duplicate the box
dup      // Stack: Box Box
// Push 1
1        // Stack: Box Box 1
// Push the word definition for @
' @      // Stack: Box Box 1 WordDef-for-@
// Create an execution token { Box WordDef-for-@ } 
// that first pushes Box and then calls @.
// The 1 argument in the stack tells "does" that it should 
// consume only one argument below 1
// in the stack.
does     // Stack: Box { Box WordDef-for-@ }
// Assign the execution token { Box WordDef-for-@ }
// to the first string comming after the invocation of variable-get-set
create   // Stack: Box
// Push 1
1        // Stack: Box 1
// Push the word definition for !
' !      // Stack: Box 1 WordDef-for-!
// Create an execution token { Box WordDef-for-! } 
// that first pushes Box and then calls !.
// The 1 argument in the stack tells "does" that it should 
// consume only one argument below 1
// in the stack.
does     // Stack: { Box WordDef-for-! }
// Assign the execution token { Box WordDef-for-! }
// to the second string comming after the invocation of variable-get-set
create   // Stack:
For instance, variable-get-set can be used as follows:
// Create a fresh variable with getter x and setter x!
variable-get-set x x!
// Create a fresh variable with getter y and setter y!
variable-get-set y y!
// Set x and y to 5 and 10, respectively.
5 x! 10 y!
// Swap variables x and y
x y x! y!
// Push x
x    // Top of stack has 10
// Push y
y    // Top of stack has 5
For more details on words create, ' <word_name>, does, refer to Sections 4.5, 4.6, and 4.7 in the Fift whitepaper. As another example of variable-get-set, the following implements a simple counter. The example uses auxiliary words reset-counter and incr-counter to reset the counter variable to 0 and increment the counter by one, respectively.
// Create the getter "counter" and setter "counter!"
variable-get-set counter counter!

// Resets the counter to 0
{ 0 counter! } : reset-counter

// Increments the counter by one.
{ counter 1 + counter! } : incr-counter

reset-counter      // counter variable has 0 
incr-counter       // counter variable has 1
incr-counter       // counter variable has 2
reset-counter      // counter variable has 0
incr-counter       // counter variable has 1
counter            // Pushes 1 to the top of the stack
Word incr-counter works as follows:
// Push the current value of counter
counter    // Stack: c
// Push 1
1          // Stack: c 1
// Add c and 1
+          // Stack: c+1
// Store the new value back into the counter variable 
counter!   // Stack: