Level 3, lesson 19

# 3.19 Assertions

You have probably seen this before: you've made a program, compiled it and it doesn't work. Then you start putting code at strategic places, trying to pinpoint the error. And when you're finally done, you've got to revisit all of these places to remove that code. And you probably forget a few..

4tH has a built-in facility which allows to put that code there, debug your program and remove the debugging code from your program by changing a single line.

It is called "assertion" and those of you who have ever worked with C probably know what we're talking about.

An assertion is a line of code that will evaluate an expression. If the expression evaluates to false, it will exit the program with an error message. Let's take a look at this simple colon-definition:

         : add                      \ expects two numbers on the stack
               +
         ;

If we call add by writing:

         1 add

it will fail. Now we add this assertion:

         assert( depth 2 >= )

It will evaluate to false when there are less than two items on the stack. The program will be terminated and the appropriate error message will be issued. You may think that this is nice, but you still have to remove all assertion manually.

Not true! If you tried this out already you will see that you won't find an assertion anywhere. It's gone! True, if you want to use assertions you have to enable them. You do that with the word '[ASSERT]':

         [assert]
         : add
               assert( depth 2 >= )
               +
         ;

         1 add

Now assertions will compile and work. If you remove the word '[ASSERT]' all assertions will disappear like they were comment. '[ASSERT]' works just like '[DECIMAL]', '[HEX]', etc. They work linear and do not follow the program flow. If you put '[ASSERT]' halfway your source-file you will notice that assertions work from that point:

         : add
               assert( depth 2 >= ) \ assertions disabled
               +
         ;

         [assert]                        \ enable assertions

         : print-hex
               base @ >r hex
               assert( depth 1 >= ) \ assertions enabled
               . cr r> base !
         ;

Assertions are only enabled in "PRINT-HEX". The assertion inside "ADD" will be removed and thus be disabled. But there is more to '[ASSERT]' than the eye meets. It doesn't enable assertions, it toggles them. When the 4tH compiler starts, assertions are disabled. The first '[ASSERT]' enables them. A second '[ASSERT]' will disable them again:

         [assert]                        \ enable assertions

         : add
               assert( depth 2 >= ) \ assertions enabled
               +
         ;

         [assert]                        \ disable assertions

         : print-hex
               base @ >r hex
               assert( depth 1 >= ) \ assertions disabled
               . cr r> base !
         ;

There are many possibilities:

- You can start testing low level colon-definitions and move your way up to the high level definitions by moving '[ASSERT]' down.
- You can enable assertions on certain parts of your code by enclosing them with an '[ASSERT]' pair.
- You can switch the entire context of '[ASSERT]'s by adding a single '[ASSERT]' to the top of your source.

You are not limited to range-checking when using 'ASSERT('. Any expression that evaluates to TRUE is allowed:

         [assert]
         : add
               assert( ." ADD starts at " here . cr true )
               assert( depth 2 >= )
               assert( ." Values: " over over . . cr true )
               +
         ;

We're sure you can come up with more useful ideas. We did too.