Blocks
A block is defined using the special words{ and }. All words listed between { and } constitute the body of the block, which is then pushed into the stack as an execution token. A block may be stored as a definition of a new Fift word by means of the word : as explained in the Words section, or executed by means of the word execute:
{ 2 * } acts as the “anonymous function” x -> 2x that gets applied twice on 17, producing the result 2 * (2 * 17) = 68. The above examples show that a block is an execution token, which can be duplicated, stored into a constant, used to define a new word, or executed.
The word ' <WORD_NAME> recovers the current definition of a word. Namely, ' <WORD_NAME> pushes the execution token equivalent to the current definition of the word <WORD_NAME>. For instance, the following two lines are equivalent:
duplicate as a synonym for the current definition of dup.
Conditional execution of blocks
Conditional execution of blocks is achieved using the wordsif, ifnot, and cond.
Word if expects a stack of the form v e, where v is a value and e is an execution token at the top of the stack. The word if consumes both e and v and executes e only if v is non-zero. If v is zero, it does nothing. Word if is roughly equivalent to the statement if (v) { e } in a high level programming language.
Word ifnot is similar to if, but instead, it executes e only if v is zero. Word ifnot is roughly equivalent to the statement if (not v) { e } in a high level programming language.
Word cond expects a stack of the form v e e', where v is a value, e and e' are execution tokens. The word cond consumes e', e and v, and executes e if v is non-zero, otherwise it executes e'. Word cond is roughly equivalent to the statement if (v) { e } else { e' } in a high level programming language.
For instance,
chksign that consumes the integer at the top of the stack and pushes either "positive", "negative", or "zero", depending on the sign of the integer.
chksign executes, here are the traces for -17 chksign, 17 chksign, and 0 chksign.
Trace for -17 chksign:
17 chksign:
0 chksign:
Loops
Fixed repeat loops
To execute a code a fixed number of times, use wordtimes. Word times expects a stack of the form e n, where e is an execution token and n is an integer at the top of the stack. The word times consumes both n and e and executes e exactly n times. If n is negative, times throws an exception.
For instance,
1 and then executes the block { 10 * } exactly 20 times, producing ((1 * 10) * 10) * 10 ..., i.e., 10^20.
The following more complex example implements the factorial function, which computes the factorial of the integer at the top of the stack:
4 fact:
Loops with an exit condition
More sophisticated loops can be created with the aid of wordswhile and until. Word while executes a block while a condition is true, and until executes a block until a condition becomes true.
Word while expects a stack of the form e e', where e and e' are execution tokens, with e' at the top of the stack. The word while consumes e and e'; then, it executes e, which produces an integer at the top of the stack, which gets consumed. If this integer is zero, while stops execution; otherwise, executes e' and begins a new loop iteration by executing e and carrying out the integer check again. Word while is roughly equivalent to the statement while (e) { e' } in a high level programming language, where e usually encodes the loop condition.
Word until expects a stack of the form e, where e is an execution token. The word until consumes e; then, it executes e, which produces an integer at the top of the stack, which gets consumed. If this integer is non-zero, until stops execution; otherwise, begins a new loop iteration by executing e and carrying out the integer check again. Usually, the last instructions in e encode the loop condition.
Here is a simple example for while:
10 repeatedly, starting from 1, but as long as the intermediate result is strictly smaller than 123. In other words, it pushes number 1000 into the stack. Here is the trace:
until:
10 repeatedly, starting from 1, but stops until the intermediate result is greater or equal to 123. It pushes number 1000 into the stack. Here is the trace:
fact-input below defines a word that computes the smallest integer that would produce a factorial bigger or equal to the integer at the top of the stack. For example, 10 fact-input produces 4, because 4! = 24 >= 10 and 4 is the smallest integer x such that x! >= 10.
10 fact-input:
Throwing exceptions
Fift uses the wordsabort and abort"<MESSAGE>" for throwing exceptions.
Word abort takes the string at the top of the stack and throws an exception with the string as the message. Similarly, abort"<MESSAGE>" throws an exception with message "<MESSAGE>" but only if the integer at the top of the stack is non-zero, which is also consumed. If the integer at the top of the stack is zero, abort"<MESSAGE>" consumes the integer but does not throw an exception.
The Fift interpreter handles exceptions by aborting all execution up to the top level and printing a message with the name of the source file being interpreted, the line number, the currently interpreted word, and the specified error message. The entire stack is cleared in the process.
For instance, word safe/ below is a safe division that checks if the divisor is zero or not. Executing 5 0 safe/ throws an exception with message “safe/: Division by zero” and clears the stack. But executing 5 2 safe/ produces 2 at the top of the stack, since 5/2 = 2 and the divisor 2 is non-zero.