[Oberon] LOOP conversion
chris at cfbsoftware.com
Wed Jan 6 23:18:51 CET 2021
> -----Original Message-----
> From: Oberon [mailto:oberon-bounces at lists.inf.ethz.ch] On Behalf Of
> August Karlstrom
> Sent: Thursday, 7 January 2021 6:43 AM
> To: oberon at lists.inf.ethz.ch
> Subject: Re: [Oberon] Re (2): LOOP conversion
> On 2021-01-06 19:41, peter at easthope.ca wrote:
> > Unrefined oberservations.
> > (1) Isomorphism exists between LOOP texts and WHILE texts.
> > (2) Loops can be nested in a tree structure. At each level there
> > be multiple loops and the number of levels is arbitrary.
> > (3) In the general case a continuation flag is needed for each
> > Eg. VAR continue0, continue1 ... : BOOLEAN;
> > (4) A LOOP having only one exit in the form "LOOP IF a THEN EXIT
> > ... END" can be replaced with "WHILE ~a DO ... END".
> > (5) A LOOP having only one exit in the form "LOOP ... IF a THEN
> > END END" can be replaced with "REPEAT ... UNTIL a".
> > (6) Pattern "LOOP statements0 IF a THEN EXIT END; statements1 END"
> > becomes "continue := TRUE; WHILE continue DO; statements0 IF a THEN
> > continue := FALSE ELSE statements1 END END".
> We should also note that this is only the first step to make the
> program compile. If comprehensibility is the goal the variables named
> "continue", "done" etc. should ideally be replaced with something
> more descriptive and specific. When skimming through the program a
> loop like
> continue := TRUE;
> WHILE continue DO
> is not very informative. After the loop we know that `continue' is
> false but what does that imply?
While it is true that LOOPs can be mechanically (or even automatically)
converted by techniques like those listed, the end result is not going to be
much of an improvement on the original, and can even be less comprehensible.
If you encounter a LOOP with multiple EXITs it should be treated as a
warning: 'BEWARE: Quick and dirty code ahead!'. If possible the code should
be 'refactored'. This involves going back to square one (the requirements)
and redesigning the algorithm.
Here is a real-life example that I tripped over in my own Component Pascal
(a superset of Oberon-2) code yesterday. Yes - I can be lazy too when the
system allows me to be :(
In the spirit of 'practise what you preach' I decided to refactor it to
eliminate the LOOP. The objective is to write an array of characters (s), to
a file, ensuring that a NULL termination character is always written, even
if the array doesn't include one:
i := 0;
LOOP ch := s[i]; Write(r, ch); INC(i);
IF ch = 0X THEN EXIT END ;
IF i = LEN(s) THEN Write(r, 0X); EXIT END
If this was mechanically converted the result would be something like this:
i := 0;
continue := TRUE;
REPEAT ch := s[i]; Write(r, ch); INC(i);
IF ch = 0X THEN continue := FALSE END ;
IF continue THEN
IF i = LEN(s) THEN Write(r, 0X); continue := FALSE END
I can see why observers might scratch their heads and not be convinced that
this was any improvement.
After some consideration, my cleaner solution is:
i := 0;
IF i = LEN(s) THEN ch := 0X ELSE ch := s[i] END;
UNTIL ch = 0X
P.S. One of the nice, subtle, improvements of Oberon-07 over Component
Pascal / Oberon-2 is noted in an additional sentence in Section 9.1 of the
Oberon Language Report:
"Strings can be assigned to any array of characters, provided the number of
characters in the
string is LESS than that of the array. (A NULL CHARACTER IS APPENDED)".
Hence, if I was writing this in Oberon-07 it might be possible to simplify
it further to:
i := 0;
ch := s[i];
UNTIL ch = 0X
More information about the Oberon