Discussion:
FOR TO BY vs FOR IN
(too old to reply)
trijezdci
2016-08-30 15:05:33 UTC
Permalink
I think removing generic FOR loops is a mistake. They are used for a lot
more than just iterating over ARRAYs and limiting them to only that will
result in inconvenience when for example summing the results obtained by
calling a function whilst doing an integration for instance.
Have you looked at the actual syntax of the FOR IN statement?

It allows ordinal range expressions, so you can also do

FOR n IN [0 .. 100] OF CARDINAL DO
sum := sum + n
END

I did't want to blow up the chart with variations of use cases, the chart has to remain generic enough to keep it all concise but here are the use cases:

(* iterating over enums and their subranges *)

FOR item IN EnumType DO ... END;

FOR item IN [v1 .. v2] OF EnumType DO ... END;

(* iterating over countable types and their subranges *)

FOR value IN CountableType DO ... END;

FOR value IN [v1 .. v2] OF CountableType DO ... END;

(* iterating over sets and multisets *)

FOR elem IN set DO ... END;

FOR elem, count IN multiSet DO ... END;

(* iterating over arrays *)

FOR index IN array DO ... END;

FOR index, value IN array DO ... END;

(* iterating over dictionaries, incl. trees *)

FOR key IN dictionary DO ... END;

FOR key, value IN dictionary DO ... END;

(* iterating over sequential lists *)

FOR item IN list DO ... END;


The FOR IN syntax also has an optional ascender or descender.

FOR item++ IN iterableExpr DO ... END;
FOR item-- IN iterableExpr DO ... END;

For enumerations, countable types and ordered collections, the default is always ascending. For unordered collections, the iteration direction is implementation defined and the use of an ascender or descender will cause a compile time error.


Note that since multisets, dictionaries and lists do not have type constructors in Modula-2 and must therefore be user defined, the use of the FOR syntax with these requires binding of an iterator procedure to the FOR statement and binding requires conformance to a blueprint for consistency and integrity.
It is also necessary to iterate repeatedly over some arrays with a
sequence of unusual strides for example in the computation of an FFT.
The FOR IN statement is actually closer to math notation than is the FOR TO BY statement. In math notation you compute the stride in the body:

99
-
\ 2 * n + 1
/
-
n = 0


FOR n IN [0 .. 99] OF CARDINAL DO
sum := sum + 2 * n + 1
END;

This is the most "natural" representation if you consider math notation to be the defining cultural context that everybody is expected to be familiar with.

The reason why the syntax of early programming languages did not closely follow the math notation and compute the stride in the header is simply because it was inefficient and compiler technology wasn't able to optimise it yet.

The required optimisation technique is called loop invariant code motion and it has been around since at least the 1970s. It is well understood and pretty standard in modern compilers.

In other words, in the days when for loop syntax with stride parameters in the loop header was first designed this was a necessary optimisation, but in our day and age doing so would be premature optimisation and thus unnecessary.
trijezdci
2016-08-30 20:18:11 UTC
Permalink
I have now split the row for the FOR statement into two: one row qualified (ordinal) and the other row qualified (collection). This way the chart covers at least two FOR statement scenarios of R10 which seems a reasonable compromise between concise and exhaustive.
r***@gmail.com
2016-09-01 22:56:30 UTC
Permalink
Hi,
I think removing generic FOR loops is a mistake. They are used
for a lot more than just iterating over ARRAYs and limiting them
to only that will result in inconvenience when for example summing
the results obtained by calling a function whilst doing an integration
for instance.
Just to state the obvious ....

Wirth removed "FOR" in the original Oberon (although it was later added
back in -2 and -07 revisions).

You don't direly need it, you can simulate it with WHILE, albeit a tiny
bit more verbose.

If I had to guess, it's because of all the corner cases and restrictions
encountered with it (esp. Pascal), but I could be wrong. (Don't modify
it from within the loop, keep it in a register, don't jump into loops,
what does it reliably contain afterwards [if anything], etc.)

I'm not really saying it's a good idea to remove, just mentioning that
it isn't always as obvious as it seems.
trijezdci
2016-09-02 01:15:53 UTC
Permalink
Post by r***@gmail.com
Wirth removed "FOR" in the original Oberon (although it was later added
back in -2 and -07 revisions).
You don't direly need it, you can simulate it with WHILE, albeit a tiny
bit more verbose.
Indeed. If simplicity of implementation was the only concern, you could dispense with WHILE, REPEAT and FOR, only providing the LOOP statement.
Post by r***@gmail.com
If I had to guess, it's because of all the corner cases and restrictions
encountered with it (esp. Pascal), but I could be wrong. (Don't modify
it from within the loop, keep it in a register, don't jump into loops,
what does it reliably contain afterwards [if anything], etc.)
We addressed all those issues in our FOR loop design.

The loop variants are implicitly declared within the loop header, they have loop scope only, the loop control variant is immutable within the loop body.


FOR n IN [0.99] OF CARDINAL DO
(* n is immutable *)
END;
(* n does is no longer in scope here *)


FOR index, value IN array DO
(* index is immutable, value is mutable *)
END;
(* index and value are no longer in scope here *)


Of course you could do a similar thing with the FOR TO BY loop, like

FOR n := 0 TO 99 OF CARDINAL DO
(* n is immutable *)
END;
(* n is no longer in scope here *)
Post by r***@gmail.com
I'm not really saying it's a good idea to remove, just mentioning that
it isn't always as obvious as it seems.
For Wirth, language design has always been custom design for a specific project on a specific platform. This affords very compact languages since you can throw out everything you are unlikely to need in your next project.

However, this is a luxury most of us cannot afford. If you design for a wider purpose you cannot as easily dispense with facilities just because you won't need them for the next project. Weighing the pros and cons becomes more involved and you are likely to have a less compact language.

Nevertheless, Modula-2 remains a very compact language even with the FOR loop.
Loading...