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: f43e6,9a0ff0bffdf63657 X-Google-Attributes: gidf43e6,public X-Google-Thread: fac41,9a0ff0bffdf63657 X-Google-Attributes: gidfac41,public X-Google-Thread: 103376,4b06f8f15f01a568 X-Google-Attributes: gid103376,public X-Google-Thread: 1108a1,9a0ff0bffdf63657 X-Google-Attributes: gid1108a1,public From: Matthew Heaney Subject: Re: Software landmines (loops) Date: 1998/09/03 Message-ID: #1/1 X-Deja-AN: 387392456 Sender: matt@mheaney.ni.net References: <902934874.2099.0.nnrp-10.c246a717@news.demon.co.uk> <6r1glm$bvh$1@nnrp1.dejanews.com> <6r9f8h$jtm$1@nnrp1.dejanews.com> <6renh8$ga7$1@nnrp1.dejanews.com> <6rf59b$2ud$1@nnrp1.dejanews.com> <6rfra4$rul$1@nnrp1.dejanews.com> <35DBDD24.D003404D@calfp.co.uk> <6sbuod$fra$1@hirame.wwa.com> <35f51e53.48044143@ <904556531.666222@miso.it.uq.edu.au> <6sgror$je8$3@news.indigo.ie> <6sh3qn$9p2$1@hirame.wwa.com> <6simjo$jnh$1@hirame.wwa.com> <6sjk3p$4tc$1@hirame.wwa.com> <6skgn4$3gq$1@hirame.wwa.com> NNTP-Posting-Date: Wed, 02 Sep 1998 23:14:11 PDT Newsgroups: comp.lang.eiffel,comp.object,comp.software-eng,comp.lang.ada Date: 1998-09-03T00:00:00+00:00 List-Id: "Robert Martin" writes: > For good reason. There are two independent program states that depend upon > N. One is whether or not we call process, and the other is whether or not > the loop exits. > > Now, we could combine them as: > > for(;;) > { > Get(N); > if (N) > > else > break; > } > > This is certainly more efficient; and if efficiency is what you need then > you'd better do this. Boy oh boy, Robert, we must come from different programming schools! The dangerous thing about the code fragment above is that the else part can get lost, especially if is long-ish. My philosophy is, handle the simple case first, then bail out: for (;;) { Get (N); if (!N) break; } When we fetch N, we're looking for that one special value, 0, that signals end of input. I prefer the organization above, because it emphasizes the special case. I don't like how you did it, because it treats the break case and the case as equals - but they are not. Your organization is telling me that N is always an integer. Process the integer one way if it's 0, and process it another way if it's positive. I feel that this is very misleading. When you , N really is a (positive) integer. But when N has the value 0, it's an end-of-input indicator (which just happens to be represented as an integer). This point is perhaps made more clear by using an end-of-input indicator that's not an integer: begin loop Get (N); ; end loop; exception when End_Error => null; end; When the user presses CNTL-D, the OS delivers to the application, which Ada.Text_IO turns into an End_Error exception. Note how similar it is to loop Get (N); exit when N = 0; ; end loop; > For example, suppose I need to flush some buffers at the end of each > iteration. I do this by calling 'flush'. I must write this as: > > for(;;) > { > Get(N); > if (N) > > > flush(); > } > else { > break; > flush(); > } > } I'm confused by your example. How does flush() get called in the else part, if it's immediately preceeded by a break? Shouldn't it be just for(;;) { Get(N); if (N) flush(); } else { break; } } If we handle the special case specially: for(;;) { Get(N); if (!N) break; flush(); } Flush gets called following , just as it does in your original fragment. > Whereas if I had lived with the double test: > > do { > Get(N); > if (N) { > > } > flush(); > } while (N); This is not the same as your original fragment, because flush gets called even if N is 0. Which behavior did you intend?