[comp.lang.misc] do...while vs. repeat...until

karl@haddock.ima.isc.com (Karl Heuer) (03/16/90)

In article <5819.25f7a840@vax1.tcd.ie> cbuckley@vax1.tcd.ie writes:
>In article <Mar.7.10.43.42.1990.17402@paul.rutgers.edu>, emuleomo@paul.rutgers.edu (Emuleomo) writes:
>> The other less serious flaw in C is the do...while contruct.
>> I kind of prefer PASCAL's repeat....until construct myself.
>
>How can this be a flaw? The two constructs are identical except for the fact
>that the condition is reversed...

That's enough to make it a (minor) flaw.  Judging from my own personal
experience, it is more natural for a test-at-top loop to specify the condition
for continuing (while), but for a test-at-bottom loop to specify the condition
for terminating (until).  I don't know if there's been a study on this; in
fact, I'm not entirely sure how to formalize the concept.

And no, I did *not* learn Pascal before C.  At worst, my opinion may be
slightly polluted from Ratfor; but I believe there's a sense in which
repeat...until is really better.

Karl W. Z. Heuer (karl@ima.ima.isc.com or harvard!ima!karl), The Walking Lint
Followups to comp.lang.misc.

pmontgom@oak.math.ucla.edu (Peter Montgomery) (03/16/90)

In article <16188@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes:
>In article <5819.25f7a840@vax1.tcd.ie> cbuckley@vax1.tcd.ie writes:
>>In article <Mar.7.10.43.42.1990.17402@paul.rutgers.edu>, emuleomo@paul.rutgers.edu (Emuleomo) writes:
>>> The other less serious flaw in C is the do...while contruct.
>>> I kind of prefer PASCAL's repeat....until construct myself.
>>
>
>That's enough to make it a (minor) flaw.  Judging from my own personal
>experience, it is more natural for a test-at-top loop to specify the condition
>for continuing (while), but for a test-at-bottom loop to specify the condition
>for terminating (until).  I don't know if there's been a study on this; in
>fact, I'm not entirely sure how to formalize the concept.

	Another problem with do..while is that we cannot access
variables declared inside the block in the loop test.  For example,
when updating a square root by Newton's method, the code

		double sqrtx, x;
		sqrtx = (some approximation to sqrt(x))
		do {
		    register const double err = x - sqrtx*sqrtx;
		    sqrtx += err/(2*sqrtx);
		} while (fabs(err) > 0.001*x);

is illegal.  Rather, we must declare "err" in a larger scope.


--------
        Peter Montgomery
        pmontgom@MATH.UCLA.EDU 
	Department of Mathematics, UCLA, Los Angeles, CA 90024

ryan@sjuphil.uucp (Patrick M. Ryan) (03/16/90)

In article <16188@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes:
>In article <5819.25f7a840@vax1.tcd.ie> cbuckley@vax1.tcd.ie writes:
>>In article <Mar.7.10.43.42.1990.17402@paul.rutgers.edu>, emuleomo@paul.rutgers.edu (Emuleomo) writes:
>>> The other less serious flaw in C is the do...while contruct.
>>> I kind of prefer PASCAL's repeat....until construct myself.
>>
>That's enough to make it a (minor) flaw.  Judging from my own personal
>experience, it is more natural for a test-at-top loop to specify the condition
>for continuing (while), but for a test-at-bottom loop to specify the condition
>for terminating (until).  I don't know if there's been a study on this; in
>fact, I'm not entirely sure how to formalize the concept.

  a simple hack to fix this problem:

#define repeat    do
#define until(c)  while (!(c))

thus,

repeat {                                   do {
    statement;        becomes                    statement;
until(condition);                          while (!(condition))

easy, no?

-- 
patrick m. ryan                                                 saint joseph's
ryan@sju.edu  /  ryan%sjuphil.sju.edu@bpa.bell-atl.com              university
{bpa|burdvax|princeton|rutgers}!sjuphil!ryan                      philadelphia
pmr@gemini.gsfc.nasa.gov                                          pennsylvania

flint@gistdev.gist.com (Flint Pellett) (03/16/90)

I have always felt that the re-use of the "while" keyword for both the
top and the bottom of a loop was a language flaw, as is reusing "break"
for both exiting cases and loops.  When you are looking at a 70-line
loop (so you can't see the whole loop on one screen) often the only
clue you have whether that "while" you are looking at is the bottom or
the top of a loop is whether or not a } preceeds the while on the same
line, and some people's coding styles don't guarantee that.  (I keep
it straight by having a while that ends a loop always have the } right
before it.) 

I have to admit to liking the construct below for loops the best: (On
any of these leaving the (condition) out is the same as if the
condition were true, except for endloop, where the default is an
unconditional branch back to the loop.) 

loop (condition)	/* keep looping as long as the condition is met */
...
outloop (condition)	/* 'break' if the condition is met */
...
reloop (condition)	/* 'continue' back at the "loop" if condition met */
...
endloop (condition)	/* exit the loop now if the condition is met */

The four keywords above make it very clear what you are doing at each step,
even when you cannot look at the entire loop at once.  (You never have to
wonder if that 'break' goes with a 'case' or with a 'while' either in
those cases where only the break is on your screen.)
-- 
Flint Pellett, Global Information Systems Technology, Inc.
1800 Woodfield Drive, Savoy, IL  61874     (217) 352-1165
INTERNET: flint%gistdev@uxc.cso.uiuc.edu
UUCP:     uunet!gistdev!flint

cet1@cl.cam.ac.uk (C.E. Thompson) (03/16/90)

In article <16188@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes:
>In article <5819.25f7a840@vax1.tcd.ie> cbuckley@vax1.tcd.ie writes:
>>In article <Mar.7.10.43.42.1990.17402@paul.rutgers.edu>, emuleomo@paul.rutgers.edu (Emuleomo) writes:
>>> The other less serious flaw in C is the do...while contruct.
>>> I kind of prefer PASCAL's repeat....until construct myself.
>>
>>How can this be a flaw? The two constructs are identical except for the fact
>>that the condition is reversed...
>
>That's enough to make it a (minor) flaw.  Judging from my own personal
>experience, it is more natural for a test-at-top loop to specify the condition
>for continuing (while), but for a test-at-bottom loop to specify the condition
>for terminating (until).  I don't know if there's been a study on this; in
>fact, I'm not entirely sure how to formalize the concept.

Time for another BCPL-was(is)-better-than-C plug. BCPL has

      WHILE expression DO command
      UNTIL expression DO command
                          command REPEATWHILE expression
                          command REPEATUNTIL expression

and of course

                          command REPEAT       /* for ever */

But you probably wanted to use some of those reserved words as variable
names, right? :-)

Chris Thompson
JANET:    cet1@uk.ac.cam.phx
Internet: cet1%phx.cam.ac.uk@nsfnet-relay.ac.uk

wittig@gmdzi.UUCP (Georg Wittig) (03/19/90)

pmontgom@oak.math.ucla.edu (Peter Montgomery) writes:

>	Another problem with do..while is that we cannot access
>variables declared inside the block in the loop test.  For example,
>when updating a square root by Newton's method, the code

>		double sqrtx, x;
>		sqrtx = (some approximation to sqrt(x))
>		do {
>		    register const double err = x - sqrtx*sqrtx;
>		    sqrtx += err/(2*sqrtx);
>		} while (fabs(err) > 0.001*x);

>is illegal.  Rather, we must declare "err" in a larger scope.

No, you needn't. The problem can be avoided easily:

		double sqrtx, x;
		sqrtx = (some approximation to sqrt(x))
		do {
		    register const double err = x - sqrtx*sqrtx;
		    sqrtx += err/(2*sqrtx);
		    if(! (fabs(err) > 0.001*x)) break;		/* HA! */
		} while (1);
-- 
Georg Wittig   GMD-Z1.BI   P.O. Box 1240   D-5205 St. Augustin 1 (West Germany)
email: wittig@gmdzi.uucp   phone: (+49 2241) 14-2294
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
"Freedom's just another word for nothing left to lose" (Kris Kristofferson)

karl@haddock.ima.isc.com (Karl Heuer) (03/22/90)

(Followups to comp.lang.misc.  I'm not talking about C; I'm talking about loop
constructs in general.)

In <OVB2S3Bxds13@ficc.uu.net> peter@ficc.uu.net (Peter da Silva) writes:
>The only sense in which repeat...until is more natural than do...while is
>if you're an assembly programmer or compiler writer [because at a low level,
>both are branch-if-false].

That's one possible justification, but it certainly isn't "the only sense" in
which it's more natural.

To take a concrete example, let's ignore the existence of <ctype.h> and
suppose that we want to test whether or not a given character is a lowercase
letter.  I claim that, to me, the condition "(c >= 'a' && c <= 'z')" is a
simpler expression than "(c < 'a' || c > 'z')".  I immediately recognize the
idiom in the former, but the latter causes a perceptible delay as I mentally
translate the condition.  (If you disagree with this example, invent another
one--unless you want to claim that there is *no* condition that is simpler
than its inverse.)

Now, my observation is that, given a condition COND which is simpler than
!COND, I am more likely to encounter the condition "do...while (!COND)" than
"do...while (COND)".  In this sense, repeat...until is the more natural
construct.

This is not a proof.  It's an observation, possibly biased (though I don't
think so) and subject to being contradicted by a more extensive study.

Karl W. Z. Heuer (karl@ima.ima.isc.com or harvard!ima!karl), The Walking Lint
________
(Note to those who keep on beating this red herring: the difference is *not*
so significant that I'm willing to use it as an excuse to switch from C to
another language; not even to that dialect of C that uses an "until" macro.
So don't bother to point out that "the preprocessor can fix it".  Do you think
you're telling me something I don't know?)

mph@lion.inmos.co.uk (Mike Harrison) (03/23/90)

In article <16249@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes:
>(Followups to comp.lang.misc.  I'm not talking about C; I'm talking about loop
>constructs in general.)
> ...
>To take a concrete example, let's ignore the existence of <ctype.h> and
>suppose that we want to test whether or not a given character is a lowercase
>letter.  I claim that, to me, the condition "(c >= 'a' && c <= 'z')" is a
>simpler expression than "(c < 'a' || c > 'z')".  I immediately recognize the
>idiom in the former, but the latter causes a perceptible delay as I mentally
>translate the condition.  (If you disagree with this example, invent another
>one--unless you want to claim that there is *no* condition that is simpler
>than its inverse.)

But how about:

    subtype LOWER_CASE_LETTERS is CHARACTER range 'a' .. 'z';

    C : CHARACTER;

    GET(C);
    if C in LOWER_CASE_LETTERS then ...

(Guess which language :-))

For loop control structures I always liked Algol 68, where you could do all
the work in the Condition part, with an empty loop body, eg:

    'while' 'if' a[i] > i 'then' i +:= 1; 'true' 'else' 'false' 'fi'
        'do'
            'skip'
        'od'

And for the ultimate in conditional expressions:

    'if' x = 1 'then' y 'else' z 'fi' := x;


Mike,


Michael P. Harrison - Software Group - Inmos Ltd. UK.
-----------------------------------------------------------
UK : mph@inmos.co.uk             with STANDARD_DISCLAIMERS;
US : mph@inmos.com               use  STANDARD_DISCLAIMERS;

meissner@osf.org (Michael Meissner) (03/24/90)

In article <4879@ganymede.inmos.co.uk> mph@lion.inmos.co.uk (Mike
Harrison) writes:

| >To take a concrete example, let's ignore the existence of <ctype.h> and
| >suppose that we want to test whether or not a given character is a lowercase
| >letter.  I claim that, to me, the condition "(c >= 'a' && c <= 'z')" is a
| >simpler expression than "(c < 'a' || c > 'z')".  I immediately recognize the
| >idiom in the former, but the latter causes a perceptible delay as I mentally
| >translate the condition.  (If you disagree with this example, invent another
| >one--unless you want to claim that there is *no* condition that is simpler
| >than its inverse.)

Three things:

    1)	On EBCDIC systems, either of the above tests would evaluate
	true for some things that are not lower case alphabetic, since
	there are some characters (10?) between 'i' & 'j';

    2)	Obviously the above test will not work for character sets that
	have more than 26 alphabetic characters;

    3)	If you are worried about micro optimization, and your compiler
	doesn't recognize the optimization, you generally get faster
	code if you rewrite the test as:

		if (((unsigned) c - 'a') <= ((unsigned) 'z' - 'a'))

	This is because only one branch is done.
--
Michael Meissner	email: meissner@osf.org		phone: 617-621-8861
Open Software Foundation, 11 Cambridge Center, Cambridge, MA

Catproof is an oxymoron, Childproof is nearly so

karl@haddock.ima.isc.com (Karl Heuer) (03/26/90)

In article <MEISSNER.90Mar24084404@curley.osf.org> meissner@osf.org (Michael Meissner) writes:
>In article <4879@ganymede.inmos.co.uk> mph@lion.inmos.co.uk (Mike Harrison) writes:
>|>To take a concrete example, let's ignore the existence of <ctype.h> and
>|>suppose that we want to test whether or not a given character is a lowercase

Watch those attributions!  Mike H. didn't say that; I did.

>Three things: [why (c >= 'a' && c <= 'z') is an imperfect test]

Agreed.  What I said above was shorthand for "for the sake of this example,
let's ignore the fact that <ctype.h> exists and is probably a better tool for
the job."

In any case, my point stands: `until' seems to be better than `while', for
most of those test-at-bottom loops where the condition is complex enough to
make a difference.

Karl W. Z. Heuer (karl@ima.ima.isc.com or harvard!ima!karl), The Walking Lint