Author Topic: The FOR Statement Gotcha!  (Read 4477 times)

0 Members and 1 Guest are viewing this topic.

Offline Donald Darden

  • Sr. Member
  • ****
  • Posts: 363
  • User-Rate: +3/-13
The FOR Statement Gotcha!
« on: July 31, 2007, 10:20:22 PM »
In some older implementations of BASIC, the FOR/NEXT loop could put you at risk of leaving the FOr variable on the stack if you did not exit the FOR loop via the NEXT statement.  The typical method of exiting incorrectly usually involved a GOTO statement, which likely was one of the reasons the GOTO has been religated to the trash heap by some programmers.  Some of those BASICs provided something like an EXIT FOR or EXIT NEXT as a way of making sure the FOR variable was removed
correctly.  Others made no provision, so you might have to force the variable to
its final value and use GOTO to jump to the NEXT statement, thereby causing a
normal exit.

There was even a problem with the scope of the FOR variable, which was only defined within the limits of the FOR/NEXT statement.  And because of the GOTO
command, you might cause a NEXT statement to accidently be associated with the wrong FOR variable when dealing with embedded FOR statements.

No wonder they called it spagetti code.

To deal with this, the BASIC syntax supported the ability to specify the specific
named FOR variable after the NEXT statement.  You could even, in some cases,
have the same NEXT statement support multiple variables, such as NEXT a,b would conclude both the a and the b FOR loops.  But this was a bit
messy, since you could not immediately pair each FOR with its own NEXT, and it
was easy to specify the variables in the wrong order (the inner loop variable
should be named first).  It also broke any indentation rules as well.

More spagetti code, aa a result.

All the PowerBasic compilers have been designed so that the FOR variables have
normal scopes (they can be GLOBAL, LOCAL, or SHARED, depending upon the
way they are declared and used elsewhere), and you can exit a FOR loop in
whatever manner you want - the results will be as expected, with no hidden
risks regarding the FOR variable or stack contents.  But any modern compiler or
interpreter should be able to make the same claim.  However, it might be worth testing just to be sure.

That is the list of the old Gotchas!  involving the FOR loop.  Now there are still some new ones that you might need to be aware of as well.  And these involve
the types of variables that you can use with a FOR statement.

For instance, you might be able to use a floating point variable as the FOR
variable, and increment with some fractional value.  This might be one example:
Code: [Select]
    FOR a! = 0 to 10 STEP 0.1
        PRINT a!
    NEXT
Now this might work with your compiler, but you might not be happy with the result.  The reason is that you specified decimal fractions, which cannot be
rendered exactly into binary form, so the increment will not be exact, and the
errors tend to accumulate with repitition, so the outcome will be only an
approximation of what you wanted.  The best solution here is to think in terms of integer values, to make your step size an integer value as well, and then there is no problem.  You can use the same principle with handling money for example,
where you do your computations in pennies, then only convert to dollars at the very end by inserting a decimal point in a string representation, or dividing by
100 and rounding to the nearest cent.

PowerBasic makes an effort to let you use any numeric type as a FOR variable,
but this is sometimes not a good idea.  Take the idea of using any type except
a LONG.  If you do this, PB compilers are optimized to handle LONGs, and in many cases, other types will be simply converted to floating point, which is far slower,
first because of the conversions, and then because floating point processing is
much slower than integer processing.

But suppose you elected to use a DWORD rather than a LONG, simply because
it can count to twice the positive value of a LONG.  How can this hurt?  Well,
what if you counted down instead of up, say from FOR a??? = 2 TO 1 STEP -1.  What would be wrong with this?  Nothing from your viewpoint, but as
PowerBasic would convert it to another form first, it would probably also do
sign correction on the STEP value because we are dealing with an unsigned
variable, and sign correction on -1 would convert it to &hFFFFFFFF.  Which is
not what we want. right?  I way would probably do this, because I've encountered this problem before, but I haven't tested it with all the compilers, so it's possible another compiler would do it differently.

Now here is another possible Gotcha! when it comes to FOR loops.  Some compilers would accept a statement like this:
Code: [Select]
    FOR a = b TO c STEP d
Some compiler won't accept this.  They will give you an error for the STEP value, as they will only accept a constant.  They may have good reasons for only
accepting a constant, such as it may result in more efficient (and faster) code,
simplify the test process used as part of the NEXT statement, and could
prevent you from accidently entering an infinite loop state (where d=0 prevents further incrementing) or trying to count through the loop backwards (where d is the wrong sign, causing a reverse increment from what was intended).

But there is another reason to avoid using d as the step, which is the way some
person might assume that the loop would work.  For instance, suppose someone
saw this code in a program:
Code: [Select]
    d = 0
    FOR a= 2 TO 1 STEP d
        PRINT a, d
        d = NOT d   
    NEXT
That person might reason that as d = 0, that the first thing done in the loop
would be to change d to -1, and that the NEXT statement would then take
-1 away from a, causing a to then be 1, and that this would satisfy the NEXT
condition and the loop would end.

What they would fail to realize is that in this case, d would only set the step
size when the FOR is processed.  Any further changes to d would have no effect
on the FOR loop itself.  So with the step size set to zero, this would be an
infinite loop, a would always be 2, and d would alternate in value between 0 and
-1.

Another Gotcha! with for loops involves the expectation that whatever b or c
is in the statement FOR a = b TO c STEP d will change the behavour of
the FOR statement automatically.  But as pointed out, the FOR only gets checked at the start, and the values of b, c, and d are then treated as constants for the duration of the FOR loop, even though the individual variables
can be changed independently.  Here is a typical case where this can become a
problem:
Code: [Select]
    FOR a = 1 TO LEN(aa$)
        aa$ = ...
    NEXT
What happens then is that if you shorten the length of aa$, you will exceed its length at some point, which can result in an error.  If you increase the length of aa$ at some point, you will not run to new full length of aa$, which can be a problem as well.

What you can do is use a bit of trickery to get around this problem in the following manner:
Code: [Select]
     a=1
     DO
        FOR a=a TO LEN(aa$)
           aa$= ...
           EXIT FOR   ' or ITERATE DO
        NEXT
     LOOP UNTIL a > LEN(aa$)


Hopefully, some of these ideas will help you avoid the pitfalls of using FOR
loops. They are generally faster than other types of loops that require your
own test and terminate steps, so learning to use this is an important step.



Offline Kent Sarikaya

  • Full Member
  • ***
  • Posts: 173
  • User-Rate: +8/-4
Re: The FOR Statement Gotcha!
« Reply #1 on: August 01, 2007, 03:50:32 AM »
These Gotcha posts are really nice, thanks Donald. I am not a low level coder or really any good at things at these depths. When strange gotcha's happen I just shrug my shoulder lost. With these posts at least I am getting an idea of all that could go on in the background depending on the compiler, stuff I never knew about. It will be nice to have these as a future reference when these pop up. Thanks for taking the time and sharing your knowledge.