#FOR…BY -1 bug
9 messages in this thread
Thanks for the reply about .key, but I still don't know why its there. Now I
have another, more serious, problem to report, The following program either
Gurus (most of the time), or fails to stop when i=0, wrapping around to i=65535
and continuing. In that case, it runs forever. If it runs forever, it does so
every time its run:
MODULE GuruCall; FROM InOut IMPORT
WriteCard, WriteString, WriteLn; VAR
i : CARDINAL; BEGIN
FOR i := 10 TO 0 BY -1 DO (* This gets the Guru almost every time *)
WriteString("Loop index = ");
WriteCard (i, 10);
WriteLn;
DEC(i);
END; (* FOR *) END GuruCall.
If the FOR-statement is replaced by the equivalent WHILE i>0…DEC(i)
construct, it works properly. It's the "BY -1" that seems to do it. "FOR i:=0
TO 10 DO" works fine. "BY 2" seems to work OK. I haven't figured out why it
Gurus sometimes and runs forever on some compiles. Linking with RTR or just RT
didn't make any difference.
I am running Kickstart 1.2 with the appropriate SetPatch, WB 1.3, the ARP
1.3 commands and library but not the ARP shell, on an Amiga 1000 with a
Starboard 2 meg on the side and four floppies, morerows, FaccII and vd0:.
Hmm, that's wierd. I'll check it out and let you know what's the deal.
The problem lies with the statement DEC(i) within the FOR loop. This is not
allowed in the Modula-2 language. Quoting from "Programming in Modula-2" 3rd
edition, page 36:
(…)
"no components of the expression determining the range must be affected by the
repeated statements, and, above all, the control variable itself must not be
changed by the repeated statements"
So basically, you cannot legally attempt to modify the variable "i" within the
scope of the FOR loop. You'll see that by removing the DEC(i) statement, all
works fine.
The language doesn't allow it but the compiler accepts it. OK. How about
this one: There is a bug in RealInOut.WriteReal. The following program: MODULE
Test; FROM TermInOut IMPORT
WriteString, WriteCard, WriteLn; FROM MathLib0 INPORT
real; FROM RealInOut IMPORT
WriteReal; VAR
A : REAL;
i : CARDINAL; BEGIN
FOR i := 1 TO 100 DO
A := real(i);
WriteString (" ("); WriteCard (i,5); WriteString (") ");
WriteReal (A, 12); WriteLn;
END; (* FOR i *) END Test.
.. produces the following (partial) output:
( 60) 60.00000
( 61) 61.00000
( 62) 62.00000
( 63) 63.00000
( 64) 640.00000
( 65) 650.00000
( 66) 660.00003
…
( 98) 980.00001
( 99) 990.00005
( 100) 100.00000 It also seems to have trouble with numbers less than 1.0.
If you download the file M2Fix.zoo from the M2S DL section, that bug will be
fixed.
The compiler must allow you to modify loop control variables from within the
FOR loop. There is no way for it to ensure that you do not. What if one of the
statements in the loop calls a procedure which then modifies the control
variable? The compiler couldn't possibly track that. although possible some
sort of run-time check might be applied (I'd have to think about that one).
Anyway, that one thing you always need to keep in mind because it is one of the
few things the compiler or runtime system can't catch (at present) in any case,
and I haven't seen an M2 compiler that catches it on any system as well.
And this: I have been encountering major weirdness in the behavior of your
compiler. For example, the following line is from a program that compiles and
runs under M2Amiga (all variables are REAL):
Sum := Sum + R[i,j]*B[j]; Under M2Sprint 1.0, the program crashes when
it reaches this point. The M2Debug that I DL'd from here claims the error
occurred in some random line of another procedure that has already executed
correctly. The line executes once (with i=3, j=4) and bombs the second time
through the loop (with i=2, j=3).
If I change the line to:
Sum := Sum + B[j]*R[i,j]; the program executes and produces correct
numbers.
Naturally, this behavior does not show up in a short test program, but only
in the real program.
This is not by any means the only problem; it's the only one reproducible
enough for me to be able to describe it.
I'd like you to send me the smallest possible code fragment that can reproduce
the problem. That's odd though, you're the only customer having so many
problems with the compiler. The few bugs that have been reported have all been
fixed in the very-near-to-be-released 1.1 update if that is any consolation.
You've already gotten your answer but I'll throw in a couple comments on the
code. Using the FOR construct handles incrementing/decrementing the loop index
so even if the DEC(i) statement was allowed you'd be decrementing the index by
TWO every time through. If that's what you want BY -2 would legally do the
job.
Another more philosophical issue. Subtraction is certainly a legitimate
operation on type CARDINAL but I am a little leery about using a non-CARDINAL
type (-1) as your index BY amount. It smacks of uncontrolled type mixing. If
I want to put negative numbers into the FOR BY I would use an INTEGER index
variable. This is just a matter of style, though. It is also a case for using
range checking. I wonder what FOR i := 10 TO 0 BY -3 would do? — Art
Might I add that I recommend never to use the FOR loop construct. It is always
faster and smaller code-wise to use either a REPEAT or a WHILE loop (see the
file M2Sprint_Tips in the READ_ME drawer for more info on this). Oberon (the
new language from Wirth) actually has removed the FOR loop alltogether.