Path: utzoo!utgpu!news-server.csri.toronto.edu!mailrus!umich!samsung!munnari.oz.au!uhccux!virtue!ccc_ldo From: ccc_ldo@waikato.ac.nz (Lawrence D'Oliveiro, Waikato University) Newsgroups: comp.lang.modula2 Subject: Re: Why are the loops so awkward? Message-ID: <747.2677cd57@waikato.ac.nz> Date: 14 Jun 90 05:45:59 GMT References: <5377.26731960@puddle.fidonet.org> <728.26767558@waikato.ac.nz> <22213@boulder.Colorado.EDU> Organization: University of Waikato, Hamilton, New Zealand Lines: 97 In <22213@boulder.Colorado.EDU>, wolniewi@boulder.Colorado.EDU (WOLNIEWICZ RICHARD HANSON) points out (in answer to my suggestion about only using zero-based arrays where it makes sense to) that Modula-2 _requires_ open arrays to be zero-based. Agreed. In which case it may be better in some cases to avoid open arrays, and resort to a lower-level technique, on the grounds that this can make the code easier to understand. The lower-level technique I'm thinking of looks like this: TYPE ArbitraryArray = POINTER TO ARRAY [0 .. 32767] OF Whatever; PROCEDURE DoSomething ( WithArray : ArbitraryArray; LowBound, HighBound : CARDINAL ); VAR Index : CARDINAL; BEGIN FOR Index := LowBound TO HighBound DO DoSomethingWith(WithArray^[Index]) END (*FOR*) END (*DoSomething*); CONST ThisLowBound = 99; ThisHighBound = 243; VAR MyArray : ARRAY [ThisLowBound .. ThisHighBound] OF Whatever; BEGIN (*Mainline*) DoSomething ( ADDRESS(CARDINAL(ADR(MyArray)) - ThisLowBound * TSIZE(Whatever)), ThisLowBound, ThisHighBound ) END (*Mainline*). So long as LowBound is never passed as zero, you won't get "underflow" problems with CARDINAL. Yeah, sure it's yucky. But I submit that there may be sometimes when this is better than the alternative. Not always, just sometimes. Hanson goes on to give reasons for using FOR, WHILE and REPEAT instead of endless-LOOP-with-EXIT: "They more clearly express the intent of the programmer, and thus make the program easier to understand in the future." This is an unwarranted generalisation. Consider the following example (it should be pretty much self-explanatory): LOOP IF NrCharsLeft = 0 THEN StringsSame := TRUE; EXIT END (*IF*); INC(SourceIndex); DEC(NrCharsLeft); IF String1[SourceIndex] <> String2[SourceIndex] THEN StringsSame := FALSE; EXIT END (*IF*) END (*LOOP*) Do you think you could write it just as simply and clearly using something other than LOOP? I don't think so. Do you think this is an unusual example? I find that, in my programs, the majority of my loops are best written using LOOP-with-EXIT rather than WHILE, REPEAT or FOR. "Avoiding EXITs makes it easier (or trivial) to determine under what conditions the loop will terminate, making post-condition verification much easier." See above example again. The third point, about compiler optimisation--I admit Hanson has a point here. But if compilers were smarter, there would be less of a need for special-case constructs, so we can then avoid burdening the language (and the programmer) with them. Loops a religious issue? Now why would that be? In my days as a Computer Science student we used to argue about this sort of thing all the time. So long as the debate stays calm and reasonable, I'm happy to take part in it! Lawrence D'Oliveiro Computer Services Dept fone: +64-71-562-889 University of Waikato fax: +64-71-384-066 Hamilton, New Zealand electric mail: ldo@waikato.ac.nz New mistakes are the only kind worth making.