Level 4, lesson 10

# 4.10 Forward declarations

It doesn't happen very often, but sometimes you have a program where two colon-definitions call each other. When you look at 4tHs source you find several examples. The throw() function calls the rpop() function, because 'THROW' takes items from the Return Stack. On the other hand, when the Return Stack underflows, it has to call 'THROW'.

There is no special instruction in 4tH to do this, like Pascals "FORWARD" keyword, but still it can be done. It even works the same way. Let's say we've got two colon-definitions called "STEP1" and "STEP2". "STEP1" calls "STEP2" and vice versa. First we create a value called "(STEP2)". We assign it the value 'MAX-N' since it is highly unlikely, there will ever be a word with that address:

         max-n value (Step2)

Then we use vectored execution to create a forward declaration for "STEP2":

         : Step2 (Step2) execute ;

Now we can create "STEP1" without a problem:

         : Step1 1+ dup . cr Step2 ;

But "STEP2" does not have a body yet. Of course, you could create a new colon-definition, tick it and assign the execution token to "(STEP2)", but this creates a superfluous entry in the symboltable.

It is much neater to use ':NONAME'. 'NONAME:' can be used like a normal ':', but it doesn't require a name. Instead, it pushes the execution token of the colon-definition it created on the stack. No, ':NONAME' does *NOT* create a literal expression, but it is just what we need:

         :noname 1+ dup . cr Step1 ; to (Step2)

Now we are ready! We can simply execute the program by calling "STEP1":

         1 Step1

Note that if you run this program, you'll get stack errors! Sorry, but the example has been taken from a Turbo Pascal manual ;).