Any operation that stores data in memory could, if given erroneous input, store data in unintended places. To guard against this, one can add range checking to words that store data. Here is an example from code we have already examined.
In the word Orders there is a word +Ocnt that increments the number in a certain slot in an array. Here is the original version:
CREATE OCNT 33 CELLS ALLOT : 'OCNT ( k - addr ) CELLS OCNT + ; : +OCNT ( k -- ) 'OCNT 1 SWAP +! ;
Notice that k must be in the range 0-32 for this to work correctly. Now here is a version that checks that k is in range:
CREATE OCNT 33 CELLS ALLOT : 'OCNT ( k - addr ) CELLS OCNT + ; : +OCNT ( k -- ) DUP 0 32 BETWEEN NOT IF CR . ." Out of Range " ABORT ELSE 'OCNT 1 SWAP +! THEN ;
There is, of course, a speed penalty for this extra checking. The original +OCNT executes 100,000 times in 26 milliseconds, while the range-checked version takes 50 milliseconds. The ranged checked version is twice as slow.
Should range-checking be included?
Range checking is obviously not necessary if a word is supplied its parameters only by other words that are guaranteed to supply valid parameters. +OCNT is a perfect example. This is a word that should NOT include range checking.
To see this, we need to look at how +OCNT is used. +OCNT occurs in the code for Orders, which calculates the orders of elements for one of the existing groups (of order 1-32). Thus, in use, the word +OCNT cannot receive an out-of-range index. If we were to use the range-checked version, the number k would be checked each time to see if it is between 0 and 32, but the test will always be true because +OCNT will never receive a k that does not satisfy this condition.
One of the virtues of producing software for your own use is that it is not so necessary to deal with bugs of the second kind (and with error trapping). It can be very time-consuming to prepare a piece of software for use by others. Those who have lived with toddlers will appreciate that it is very much like "child proofing" a house. How much you have to do depends both on the complexity of your house and the sophistication of your toddler. Rather than put all your possessions in locked cabinets, however, you must give thought to what precautions are really most effective.
The critical words to consider for range checking (or other error trapping) are words such as Perm: that get input from the user and store things in memory. These are the words that have the potential to alter the code itself. In the final version of the permutations package, I not only use a range-checked version of Send! but I also include other tests to make sure that the input string has the correct form.
At the beginning of the preceding section, we used the example of G*. It would not be efficient to put range checking into a word like this, which is used very frequently. It would be better to examine the code that passes information to such words, making sure that G* will not receive invalid input. Once the internal code of the system is correct, the only source of invalid data will be input routines. This is usually the best place to put error traps. Since data entry is slow anyhow, error traps here will not significantly slow the system. Once we are sure that the input routines will not send incorrect data to the rest of the system, it should not be necessary to have error traps on lower level words.