From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.3 required=5.0 tests=BAYES_00,INVALID_MSGID autolearn=no autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: fac41,f66d11aeda114c52 X-Google-Attributes: gidfac41,public X-Google-Thread: 103376,f66d11aeda114c52 X-Google-Attributes: gid103376,public From: mheaney@ni.net (Matthew Heaney) Subject: Re: Building blocks (Was: Design By Contract) Date: 1997/10/04 Message-ID: #1/1 X-Deja-AN: 278137217 Distribution: world References: <34316EC3.5B62@dynamite.com.au> <199710011402.QAA02444@basement.replay.com> <3432788C.E35@uk.ibm.com> Organization: Estormza Software Newsgroups: comp.lang.ada,comp.lang.eiffel Date: 1997-10-04T00:00:00+00:00 List-Id: In article , Paul Johnson wrote: >>(One of the while-loop problem is that for a tidy >>record processing program you have to write >> record = file.read() >> Do while(~file.eof()) >> thing.accept(record) >> record = file.read() >> End while >>) > >I know that this was an aside, but it still puzzles me. Surely it will >be wrong if the file is empty: there will be no record to read. The >correct version (in Eiffel) would be > > from file.open("foo") until file.eof loop > thing.accept (file.record) > end -- loop > >If you have to read a dummy record before file.eof becomes valid then >you have a badly designed file object. That's the idiom in Ada too: while not End_Of_File (F) loop Read (F, X); ; end loop; I think the original example, though, was this: read some numbers from the user interactively, process each one at a time, and stop processing when the user enters a zero. In Ada, it would be loop Read (N); exit when N = 0; ; end loop; This is a very clean solution, and in the Soloway paper, they showed that there were fewer errors using this loop structure compared to a loop which disallows an exit from the middle. Something like: Read (N); while N /= 0 loop Read (N); end loop; The issue here is that the read statement must be written twice. Exiting from the middle is a more natural idiom for certain problems. So don't assume that there's a "badly designed" file, because we might not be literally talking about a file. That the loop termination depends on what you've read (the "dummy" value) is a common occurrence, and the simplest loop idiom in this case is: loop exit when end loop; A while loop is more complex and error prone solution for this type of problem. Soloway showed that there was a statistically significant difference between two populations, one using a test-at-the-top, and the other using a test-in-the-middle, with the latter group having fewer errors. The reference is: Coginitive Strategies and Looping Constructs: An Empirical Study Elliot Soloway et al CACM, Vol. 26, No. 11, Nov 83, p. 853 - 860 A typical example of termination depending on input is a scanner. If you're scanning an identifier (say), then you exit when you've read some whitespace: Scan_Identifier: loop exit Scan_Identifier when end loop Scan_Identifier; Another common idiom is a linear search. When you find the item you're looking for, bail out: Find_Item: declare Found : Boolean := False; Position : Positive range Items'Range; begin for Index in Items'Range loop if Items (Index) = Item then Position := Index; Found := True; exit; end if; end loop; if Found then else end if; end Find_Item; Exiting from the middle of a loop also shows up in functions as an early return: function Position (Items : Item_Array; Item : T) return Natural is begin for Index in Items'Range loop if Items (Index) = Item then return Index; end if; end loop; return 0; -- means Item not found end; In none of these cases is the "file" badly designed. -------------------------------------------------------------------- Matthew Heaney Software Development Consultant (818) 985-1271