<< Home | About Forth | About TurboForth | Download | Language Reference | Resources | Tutorials | YouTube >>


Enhanced CASE Construct

The CASE structure in Forth is not so great. Consider the following code:

: TEST ( n -- )
  CASE
    1 OF 100 ENDOF
    2 OF 200 ENDOF
    3 OF 300 ENDOF
    999 \ any other case
  ENDCASE
  .
;

If you try the above code, it works for the explicit cases of 1, 2, and 3. However, it doesn't work for the 'catch all'. If you try the example above and pass in a value of 7, instead of getting 999 you get your 7 back. Why? It's because ENDCASE performs a DROP (among a lot of other stuff) which means that the 999 gets dropped, whereas the selector (n) should actually be dropped. Consider the same code without a default case:

: TEST ( n -- )
  CASE
    1 OF 100 ENDOF
    2 OF 200 ENDOF
    3 OF 300 ENDOF
  ENDCASE
  .
;

If you try it, you'll see that (correctly) if you pass 1, 2, or 3, you get 100, 200, and 300, and crucially you do not get back the value that you passed in. It's been cleaned up for you. This is correct, and is by design. Note that if you pass a value in that is not caught by one of the cases then you actually get a stack underflow. That's your fault! Your code should have caught all the cases, or provided a default case.

But hang on, we provided a default case, in the first code example, and it didn't work. So how we can we make it work?

The secret is to include an extra OF...ENDOF clause, with a DUP in front of it, like this:

: TEST ( n -- )
  CASE
    1 OF 100 ENDOF
    2 OF 200 ENDOF
    3 OF 300 ENDOF
    DUP OF 999 ENDOF \ any other case
  ENDCASE
  .
;

If you try the above, you'll find it works fine. Any value that is not 1, 2, or 3 results in 999 being produced. Hardly intuitive, though, is it?

It's possible to improve the standard Forth syntax (the way CASE et al works in TurboForth is in accordance with the ANS94 standard) with a simple change to ENDCASE. And, because, in Forth, we can redefine words and have them use their previous self, we'll use that to our advantage. The following introduces (in this author's opinion) a dramatic improvement to the syntax:

This introduces a new word, called DEFAULT: which is used as follows:

: test 
  case
    1 of 100 endof
    2 of 200 endof
    3 of 300 endof
    default: 999
  endcase
  .
;

This, in this author's opinion, makes the code much more readable. The guess work from the previous example has been removed, and it is completely clear on the intent of the code. Refer to the default case in the previous example:

   DUP OF 999 ENDOF \ any other case

If the comment saying "any other case" were absent, would you know, for sure, what its intent was? Maybe, if you were intimately familiar with the internal workings of CASE and its associated words, but otherwise, you might have to test it to try it out.

Aknowledgements

Thanks go to the crowd on comp.lang.forth, for helping with my misunderstanding brain-fade and inspiring the above code.

14th October 2013


<< Home | About Forth | About TurboForth | Download | Language Reference | Resources | Tutorials | YouTube >>