Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Wanted: Utility to take gotos away.

7 views
Skip to first unread message

Jim Frost

unread,
Jul 7, 1994, 4:14:10 PM7/7/94
to
jrob...@ua1ix.ua.edu (Jeff Robertson) writes:
>I once read a _SERIOUS_ article in, I believe, Softalk (the old Apple II
>magazine), in reference to BASIC, that advocated replacing statements

>like
> if a=b then goto 21030
>with
> if a=b then 21030
>
>claiming that this was beneficial because it eliminated GOTO's.
>I am not making this up. It was not an April issue. The author
>was not making any subtle points about tokenization or source code
>size. He believed that this was removing a GOTO and therefore was
>good. Really.

I'm pretty certain that you're misinterpreting the author's intent,
despite your "subtle points about tokenization" statement.

In many interpreted versions of BASIC the "then goto <line>" construct
is exactly equivalent to "then <line>", but contains one extra token.
This extra token must be interpreted each time the line is executed --
resulting in a performance loss. It was, therefore, common practice
to leave out extraneous keywords whenever possible. I know I did this
a lot when using Applesoft, especially in this particular (common!)
case.

It is possible that the author was completely deluded, but this hits
so close to home that I would have a hard time believing that such a
glaring mistake would make it past any editor worth his title.

On this topic, another performance-enhancing trick was to put
subroutines early in the program execution. This was done because it
was common for BASIC interpreters to put each code line in a linked
list, then search the list from top to bottom when a "goto" or "gosub"
was encountered. By putting subroutines early in the program the
searches were shorter. I don't recall doing this in Applesoft, but it
did yield observable performance benefits in CBM (Commodore) BASIC.

Having said all that, I for one am opposed to the elimination of goto.
I use the construct very rarely, but it is quite reasonable, readable,
and clear to use it as a loop escape mechanism -- ESPECIALLY in nested
loops. The alternative of providing an additional loop conditional is
one that impacts both performance and readability.

jim frost
ji...@centerline.com

Craig Dickson

unread,
Jul 8, 1994, 4:20:37 AM7/8/94
to
In article <2vhnmi$l...@wcap.centerline.com>,
Jim Frost <ji...@centerline.com> wrote:

|Having said all that, I for one am opposed to the elimination of goto.
|I use the construct very rarely, but it is quite reasonable, readable,
|and clear to use it as a loop escape mechanism -- ESPECIALLY in nested
|loops. The alternative of providing an additional loop conditional is
|one that impacts both performance and readability.

Well, a goto is not *necessarily* the *worst* way to handle any given
situation; but in a reasonable language (not, for instance, Pascal), it
is almost never the best, and I would be in favor of getting rid of it
because it is generally used in inexcusably lame ways that damage the
readability of code. I have known people who used goto's *habitually*,
not because it made the code any better, but because it required less
thinking than any of the alternatives.

Horror of horrors: I once knew a C programmer who implemented *all*
his loops with goto's. He cheerfully described himself as an assembly
language programmer forced to use a C compiler. His code was known
to be useful in cases of food poisoning, as exposure to it generally
induced vomiting.

Whenever I have been working in C or C++ and been tempted to use a goto,
I have preferred, if I could afford the time, to rewrite the function
to some degree (sometimes from scratch) to avoid creating the situation
in which the goto became desirable. The result of this has generally
been to improve the function significantly in both readability and
efficiency, because what made the goto necessary was poorly-thought-out
code that did not properly reflect everything the function needed to do,
i.e. it had been structured improperly. Thus, from my own experience, I
regard the use of a goto in structured code as an almost certain
indication of poor design.

Referring to loop escape mechanisms -- I've heard that argument before,
and I still disagree with it. Let's take a situation like this:

struct frotz *pointers[];

void mumblefrotz(int b)
{
int a, c;

for (a = 0; a < b; a++)
{
for (c = a; c < b; c++) // sorry, bad pun there!
{
while (pointers[a][c])
{
if (pointers[a][c]->magic != 0xDEADBEEFUL)
goto done;

// use pointers[a][c] for whatever
}
}
done:
}
}

This is a fairly straightforward canonical "I need a goto" loop escape
situation. From within the while loop, you want to jump out not only of
the while loop itself, but also the for loop that encloses it. C doesn't
have a keyword to do that, though; 'break' would get you out of the while
loop, but you'd then still be in the inner for loop, and you'd have to
test the condition again to determine whether to keep going. I'll agree
that a goto is preferable to that, though usually the extra test and
branch involved would not impact performance in any meaningful way; the
code has been running around in a loop for a while already, so adding
another test/branch is unlikely to increase the function's execution time
by any significant amount. From the standpoint of readability, both the
extra test/branch and the goto are grotesque; which one is better depends
on whether your image of Edsgar Dykstra stops short of godhood.

But what if we write it this way:

struct frotz *pointers[];

void loopfrotz(int a, int b)
{
int c;

for (c = a; c < b; c++) // sorry, bad pun there!
{
while (pointers[a][c])
{
if (pointers[a][c]->magic != 0xDEADBEEFUL)
return;

// use pointers[a][c] for whatever
}
}
}

void mumblefrotz(int b)
{
int a;

for (a = 0; a < b; a++)
{
loopfrotz(a, b);
}
}

This, I would say, is clearly more readable than either the goto version
given above, or the alternative of replacing the goto with two tests and
branches. It is less efficient, in that you're going through subroutine
call overhead for each iteration of the main for loop, but in the real
world, at least nine times out of ten that's insignificant. As we all
know, just about any program will have a relatively small amount of code
that actually impacts performance in any meaningful way. In that part of
the program, you'll be more concerned with efficiency as you decide how
to write the code. You may even want to write all or part of that code
in assembler so that you'll have a finer degree of control over the
resulting object code. But for the other 90% or so of the program, you're
better off going for readability over speed.
--
Craig Dickson (c...@netcom.com): a collector and cataloger of net.butterflies.
Keeper, alt.usenet.kooks FAQ. Coordinator, Kook of the Month Awards (a.u.k).
KotM archives, a.u.k FAQ, and net.legends FAQ: ftp://ftp.netcom.com/pub/crd.
Whish! A gull. Gulls. Far calls. Coming, far! End here. Us then. Finn, again!

Janne Kukonlehto

unread,
Jul 8, 1994, 8:26:33 AM7/8/94
to
Jim Frost (ji...@centerline.com) wrote:
> Having said all that, I for one am opposed to the elimination of goto.
> I use the construct very rarely, but it is quite reasonable, readable,
> and clear to use it as a loop escape mechanism -- ESPECIALLY in nested
> loops. The alternative of providing an additional loop conditional is
> one that impacts both performance and readability.

I personally think that in Perl you can implement loop escapes
nicer. It allows labeling loops and the loop control statements "next"
and "last" (Perl equivalents of C "continue" and "break") can take a
label as a parameter (Perl allows also normal goto). Here's an
example:

myloop1:
while(!$done)
{
for(@items)
{
if($_ eq "error") last myloop1;
}
}

Now, I really would like to see C-compilers to implement equivalent of
this. Something like following:

myloop1:
while(!done)
{
for(i=0;i<items_count;i++)
{
if(strcmp(items[i],"error")==0) break myloop1;
}
}

Shouldn't be too hard to implement? I think this construct is much
more self-documenting than a goto jump and it is a shame that C
currently allows you to break only the innermost loop.

I think the C++ exception handling might also be a good way to avoid
the use of goto. Anyone who knows something about it?

--
Janne Kukonlehto*jtkl...@stekt.oulu.fi*http://stekt.oulu.fi/~jtklehto

Paul Tomblin

unread,
Jul 8, 1994, 9:49:58 AM7/8/94
to

In a previous article, ji...@centerline.com (Jim Frost) said:
[replacing "if foo then goto 000" with "if foo then 000" to eliminate gotos]

>
>It is possible that the author was completely deluded, but this hits
>so close to home that I would have a hard time believing that such a
>glaring mistake would make it past any editor worth his title.

You *seriously* over estimate the intelligence of the people who were editing
magazines for toy computers back then. I have seen similar claims and
equally stupid articles in magazines like "Compute", "RUN", and "TPUG".
"Transactor" at least was technically with-it.

>On this topic, another performance-enhancing trick was to put
>subroutines early in the program execution. This was done because it
>was common for BASIC interpreters to put each code line in a linked
>list, then search the list from top to bottom when a "goto" or "gosub"
>was encountered. By putting subroutines early in the program the
>searches were shorter. I don't recall doing this in Applesoft, but it
>did yield observable performance benefits in CBM (Commodore) BASIC.

Having extensively hacked in Commodore Basic, I can tell you it's not that
easy. The BASIC interpeter looked at the HIGH BYTE of the two byte line
number, and if it was greater than the current line numbers high byte, it
would start scanning forward, otherwise it would start scanning from the
front of the program. So it paid to have the subroutine or goto target
immediately after the current line, but only if the line number was more than
256 greater than the current line number.

Which is why my goto targets were always line number on even thousands.

And don't ask me why I still remember this crap - I haven't used basic in 8
years!

--
Paul Tomblin, Freenet News screwup^H^H^H^H^H^H^HAdministrator
"When longing becomes loVe/When night turns to day/Everything changes/Joy
will find a way." bRuce Cockburn.
"I'll need daily status reports on why you're so behind" - Dilbert's boss

Nick Kramer

unread,
Jul 8, 1994, 9:50:12 AM7/8/94
to
[alt.folklore removed from send list]

Excerpts from Craig Dic...@netcom.com

> This is a fairly straightforward canonical "I need a goto" loop escape
> situation. From within the while loop, you want to jump out not only of
> the while loop itself, but also the for loop that encloses it. C doesn't
> have a keyword to do that, though; 'break' would get you out of the while
> loop, but you'd then still be in the inner for loop, and you'd have to
> test the condition again to determine whether to keep going.

What you really want is a non-local exit. In my prefered language of
the day (Dylan), there's a construct called a block which provides just
that. Your example could be rewritten as

for (a =...)
block (quit-this-loop)
for (c = ...)
while (pointers[a,c])
if (condition)
quit-this-loop;
end if;
end while;
end for;
end block;
// Continue doing things
end for;

The block construct actually serves several functions, but 98% of the
time it's a local exit. It's nice because it gives you some kind of
warning that a non-local exit may happen. With goto, you have no
warning, nor any limitations on the scope of the label and thus places
where it could potentially be used from.

-Nick Kramer

Olaf Seibert

unread,
Jul 8, 1994, 8:34:37 PM7/8/94
to
If I'm in a silly mood, I do

#define branchto goto /* Avoid gotos */

-Olaf.
--
___ Olaf 'Rhialto' Seibert <rhi...@mbfys.kun.nl> PGP key fingerprint:
\X/ I'm not weird, I'm differently percepted. D787B44DFC896063 4CBB95A5BD1DAA96

Paul Guertin

unread,
Jul 8, 1994, 9:24:33 PM7/8/94
to
In article <crdCsM...@netcom.com> c...@netcom.com (Craig Dickson) writes:
>In article <2vhnmi$l...@wcap.centerline.com>,
>Jim Frost <ji...@centerline.com> wrote:
>
>Referring to loop escape mechanisms -- I've heard that argument before,
>and I still disagree with it. Let's take a situation like this:
>
>struct frotz *pointers[];
>void mumblefrotz(int b)
>{
> int a, c;
> for (a = 0; a < b; a++)
> {
> for (c = a; c < b; c++) // sorry, bad pun there!
> {
> while (pointers[a][c])
> {
> if (pointers[a][c]->magic != 0xDEADBEEFUL)
> goto done;
> // use pointers[a][c] for whatever
> }
> }
> done:
> }
>}
>
>But what if we write it this way:
>
>struct frotz *pointers[];
>void loopfrotz(int a, int b)
>{
> int c;
> for (c = a; c < b; c++) // sorry, bad pun there!
> {
> while (pointers[a][c])
> {
> if (pointers[a][c]->magic != 0xDEADBEEFUL)
> return;
> // use pointers[a][c] for whatever
> }
> }
>}
>
>void mumblefrotz(int b)
>{
> int a;
> for (a = 0; a < b; a++)
> {
> loopfrotz(a, b);
> }
>}
>
>This, I would say, is clearly more readable than either the goto version.

When a and c are closely-related variables (say x and y coordinates in a
2D plane), I find the first version more readable than the second.
Artificially creating a function for the sole purpose of eliminating a
goto isn't the best solution in this case, IMHO.

If you feel so strongly about gotos used to exit loops, you shouldn't
use break and continue statements in loops, since they are merely gotos
in disguise.

I think that if C provided a break(n) statement to get out of the
n innermost loops, the goto statement would become superfluous.
But it doesn't, and we have to make do with what we have.

Paul Guertin
guer...@iro.umontreal.ca

Craig Dickson

unread,
Jul 9, 1994, 6:46:57 AM7/9/94
to
In article <CsnFw...@iro.umontreal.ca>,
Paul Guertin <guer...@IRO.UMontreal.CA> wrote:

|If you feel so strongly about gotos used to exit loops, you shouldn't
|use break and continue statements in loops, since they are merely gotos
|in disguise.

Rubbish. A break or continue statement totally lacks the characteristic
that makes the goto statement dangerous: the ability to go *anywhere*,
without any reference to the structure of the code. In contrast, break
and continue are quite limited in capability, and by definition forced
to work within the structure of the code rather than violating it.

The "gotos in disguise" argument has been used often, usually by people
who didn't know what they were talking about. I recall one impressively
dimwitted essay in one of the hobbyist magazines around ten years ago
that argued that there's nothing wrong with goto's because your nice,
structured HLL code, when compiled, is full of JMP instructions anyway.
This person had obviously totally missed the point.


--
Craig Dickson (c...@netcom.com): a collector and cataloger of net.butterflies.

KotM archives, a.u.k FAQ, and Net.Legends FAQ: ftp://ftp.netcom.com/pub/crd.


Whish! A gull. Gulls. Far calls. Coming, far! End here. Us then. Finn, again!

"Inscrutable people tend to drink inscrutable beer." -- Elizabeth of Windsor.

Juergen Nickelsen

unread,
Jul 9, 1994, 8:03:00 AM7/9/94
to
In article <CsnFw...@IRO.UMontreal.CA> guer...@IRO.UMontreal.CA
(Paul Guertin) writes:

> I think that if C provided a break(n) statement to get out of the
> n innermost loops, the goto statement would become superfluous.
> But it doesn't, and we have to make do with what we have.

IMHO a break(n) would not be optimal in terms of readability and
maintainability of the code. I'd rather favour a "break <label>" to
break out of a loop construct <label>. This is in fact a goto in
disguise (although no more than a break(n)), but in this restricted
form it shouldn't be too bad.

On the other hand, a break(n), where n is a *variable*, should enable
_lots_ of extremely creative uses. Sounds like a meta control
structure to me. Probably the IOCCC would benefit a lot from that.

--
Juergen Nickelsen

Raul Deluth Miller

unread,
Jul 9, 1994, 11:00:29 AM7/9/94
to
Craig Dickson:
. Rubbish. A break or continue statement totally lacks the
. characteristic that makes the goto statement dangerous: the ability
. to go *anywhere*, without any reference to the structure of the
. code. In contrast, break and continue are quite limited in
. capability, and by definition forced to work within the structure
. of the code rather than violating it.

While that may be literally true in some restricted sense, the use of
C's break or continue in conjunction with the structure of the code
with which they must appear gives the same ultimate ability as goto.

Consider the following:

{
int line= 10;
while (1) switch (line) {
case 10: ...
case 20: ...
case 30: ...
case 40: ...
case 50: ...
case 52: ...
case 55: ...
case 60: ...
case 70: ...
case 100: ...
etc.
}
}

In this context, the association of a number with a symbol combined
with the use of either break or continue has exactly the significance
of a goto. Of course, you aren't going to get the effect of a
longjump() this way, but you wouldn't get that with goto either.

And this property isn't all that C specific either. 'case' may be
considered to be syntactic sugar for 'else if'.

Raul D. Miller n =: p*q NB. prime p, q, e
<rock...@nova.umd.edu> NB. public e, n, y
y =: n&|&(*&x)^:e 1
x -: n&|&(*&y)^:d 1 NB. 1 < (d*e) +.&<: (p,q)

James Michael Chacon

unread,
Jul 9, 1994, 2:37:00 PM7/9/94
to
c...@netcom.com (Craig Dickson) writes:

>In article <CsnFw...@iro.umontreal.ca>,
>Paul Guertin <guer...@IRO.UMontreal.CA> wrote:

>|If you feel so strongly about gotos used to exit loops, you shouldn't
>|use break and continue statements in loops, since they are merely gotos
>|in disguise.

>Rubbish. A break or continue statement totally lacks the characteristic
>that makes the goto statement dangerous: the ability to go *anywhere*,
>without any reference to the structure of the code. In contrast, break
>and continue are quite limited in capability, and by definition forced
>to work within the structure of the code rather than violating it.

But the simple fact is, is that C goto's can't go *anywhere*. They can only
go somewhere else in the current function scope which if written properly
should be easy enough to follow. That tends to make the goto also work
within the structure of the code as well...Gee seems according to your
logic goto's in C are fine as well. This knee-jerk reaction that
"ALL GOTO'S CONSIDERED BAD!!!. MUST DESTROY!" just is making less and less
sense. The fact that it is called a goto seems to be the only reason you
dislike it so much and would just rather write extra confusing code just
to avoid their use.

>The "gotos in disguise" argument has been used often, usually by people
>who didn't know what they were talking about. I recall one impressively
>dimwitted essay in one of the hobbyist magazines around ten years ago
>that argued that there's nothing wrong with goto's because your nice,
>structured HLL code, when compiled, is full of JMP instructions anyway.
>This person had obviously totally missed the point.

As have you...The simple fact that is called "goto" seems to be the only
reason you dislike it. This isn't BASIC anymore where you could just
jump anywhere (I have seen spaghetti code in BASIC that was totally
unitelligable this way), since the language restricts it's use.

James

Craig Dickson

unread,
Jul 9, 1994, 3:52:09 PM7/9/94
to
In article <ROCKWELL.9...@nova.umd.edu>,

Raul Deluth Miller <rock...@nova.umd.edu> wrote:

|Craig Dickson:
|. Rubbish. A break or continue statement totally lacks the
|. characteristic that makes the goto statement dangerous: the ability
|. to go *anywhere*, without any reference to the structure of the
|. code. In contrast, break and continue are quite limited in
|. capability, and by definition forced to work within the structure
|. of the code rather than violating it.
|
|While that may be literally true in some restricted sense, the use of
|C's break or continue in conjunction with the structure of the code
|with which they must appear gives the same ultimate ability as goto.

No, it does not. Keep reading...

|Consider the following:
|
| {
| int line= 10;
| while (1) switch (line) {
| case 10: ...
| case 20: ...
| case 30: ...
| case 40: ...
| case 50: ...
| case 52: ...
| case 55: ...
| case 60: ...
| case 70: ...
| case 100: ...
| etc.
| }
| }

I think what you have in mind here is a finite state machine, with the
value of 'line' being changed as needed within each case so that the
as the flow of control loops around, it goes through each case in an
arbitrary sequence. So you're claiming that this is somehow equivalent
to a goto, right? It isn't. In your example, because a 'break' only
occurs within the switch statement, it is impossible to escape the
enclosing while loop. A goto could easily do so. Also, note that a
'break' from anywhere inside the switch statement can only go to one
place: the end of the switch. Gotos are not so restricted; you can put
the target label anywhere you like within the function. This is the
sort of thing I mean when I say that gotos can violate structure, while
'break' is forced to work within structure.

|And this property isn't all that C specific either. 'case' may be
|considered to be syntactic sugar for 'else if'.

Never written a C compiler, have you? 'Case' is *not* syntactic sugar.
Syntactic sugar is something that adds *no* functional improvement in
the language, but which humans like for aesthetic reasons. The array
index operator is a good example of this: pointer[x] is exactly the
same as *(pointer + x). The compiler generates the same code for both.

In contrast, while switch statements are often compiled as a series of
if/else operations, they need not be. Many compilers will, under the
right circumstances, implement cases as entries in a jump table. This
can improve performance and reduce the size of the compiled code. Also,
one case can fall through to another, which would be impossible to
express using cascaded if/else syntax.

Craig Dickson

unread,
Jul 9, 1994, 5:24:06 PM7/9/94
to
In article <2vmqoc$2...@nbc.ksu.ksu.edu>,

James Michael Chacon <j...@ksu.ksu.edu> wrote:

|But the simple fact is, is that C goto's can't go *anywhere*. They can only
|go somewhere else in the current function scope which if written properly
|should be easy enough to follow.

Pardon my imprecision on that point. I was thinking at the single-function
level, so in that sense I was correct to say "anywhere", but I didn't
make it clear that I intended it that way. Yes, gotos only work within
a function. They can, however, go anywhere within that function, without
regard for the structure of the code.

|That tends to make the goto also work
|within the structure of the code as well...

It's certainly possible to use a goto in a non-structure-violating way,
but in that case, you probably don't need to use a goto. You could, for
instance, use a goto in place of a 'break' statement to exit a loop or
case statement, but it would be a silly thing to do.

|Gee seems according to your logic goto's in C are fine as well.

Then you did not understand my logic.

|The fact that it is called a goto seems to be the only reason you
|dislike it so much

No, the name 'goto' is irrelevant. If it were called something else, but
still behaved the same way, I would still dislike it. You seem to have
failed to grasp the point I was making, if all you can get out of my
article is that I seem to dislike the word itself.

|and would just rather write extra confusing code just
|to avoid their use.

Nonsense. If you found my example confusing, that says more about your
understanding of C than anything else. As for 'extra', my only change
was to break out the two inner loops into a separate function. If you
consider that a lot of 'extra' work, then I suppose you'd rather just
write your entire program in main() and use goto's to get around? After
all, this business of breaking things out into separate functions is
just a lot of extra work, right?

|This isn't BASIC anymore where you could just
|jump anywhere (I have seen spaghetti code in BASIC that was totally
|unitelligable this way),

I've seen code in C that was totally unintelligible this way. If you
haven't, then I'm glad you've been spared such an unpleasant experience.
But it certainly can be done, and has been done in allegedly professional
code used in commercial products.

|since the language restricts it's use.

Not nearly enough, IMO. To the extent that the functionality of 'goto'
is desireable, it is implemented more safely by 'break', 'continue',
and 'return'.

John William Chambless

unread,
Jul 9, 1994, 9:48:32 PM7/9/94
to
In article <CsnDL...@sci.kun.nl>, Olaf Seibert <rhi...@mbfys.kun.nl> wrote:
>If I'm in a silly mood, I do

>#define branchto goto /* Avoid gotos */

Once, on an assignment that was due in a few hours, I bailed
out of an error condition with a goto. Careful commenting
saved me from a knee-jerk F.

if(blargfart(err_status))
goto BAILOUT; /* !considered(harmful) */

The program ran great, and I got my A!

My personal prejudice (isn't that what this discussion REALLY is about?)
is that if a GOTO makes the code clear, and the label is VERY close to
the GOTO (in the same screenful) it's okay.

The odd thing is that C has a better-implemented goto
than most languages, and you almost never (I can hear Craig saying
"ABSOLUTELY NEVER") really need to use it.

--
* Billy Chambless University of Southern Mississippi
* On the Internet, nobody knows you're a cop.

Darin Johnson

unread,
Jul 9, 1994, 11:11:03 PM7/9/94
to
> |And this property isn't all that C specific either. 'case' may be
> |considered to be syntactic sugar for 'else if'.

Yeah, and all those structured concepts are just syntactic sugar
for the computed goto :-)
--
Darin Johnson
djoh...@ucsd.edu
Where am I? In the village... What do you want? Information...

Tom Lane

unread,
Jul 9, 1994, 11:04:08 PM7/9/94
to
nic...@prz.tu-berlin.de (Juergen Nickelsen) writes:
> guer...@IRO.UMontreal.CA (Paul Guertin) writes:
>> I think that if C provided a break(n) statement to get out of the
>> n innermost loops, the goto statement would become superfluous.
>> But it doesn't, and we have to make do with what we have.

> IMHO a break(n) would not be optimal in terms of readability and
> maintainability of the code. I'd rather favour a "break <label>" to
> break out of a loop construct <label>. This is in fact a goto in
> disguise (although no more than a break(n)), but in this restricted
> form it shouldn't be too bad.

Quite so. The first language I did serious programming in was Bliss-11,
circa 1973. It did not have goto. It did have a "break <label>"
construct, which could be used to exit any surrounding block (not only
loop statements, but any control structure). In the twenty years since
then, I don't think I've ever felt the need to write a goto that wasn't
equivalent to a break <label>.

C is deficient in several respects: not only exiting more than one nested
loop, but also you can't exit a loop from within a contained "switch"
(because of the overloaded use of "break"). Another situation which C
can't solve without goto, but break <label> can, is where you have
post-loop cleanup code that has to be bypassed in case of a premature
exit. For example, to scan a list and create a new entry if no match
is found:

labelx: begin
for (ptr = listhead; ptr != NIL; ptr = ptr->next) {
if (ptr->ID == wanted_ID) break labelx;
}
// code here to insert a new entry for wanted_ID
end

This mixes elements of several languages, but I hope it gives the idea.

I regard this as perfectly well structured code. Nor do I have the
slightest compunction about writing such a goto, if the language doesn't
provide the construct I need. Structured programming is not defined as
"C-without-goto".

> On the other hand, a break(n), where n is a *variable*, should enable
> _lots_ of extremely creative uses. Sounds like a meta control
> structure to me.

That would be equivalent to a "computed goto" a la Fortran; it would
negate every advantage of goto-less programming from both the programmer's
and compiler's points of view, because control flow couldn't be
determined until run-time. I don't see any value in it.

An exception mechanism (as in C++ or Ada) generally will do for
situations where you really need run-time-determined control flow.
However, exceptions are FAR more complex than ordinary fixed-branch-
destination structured programming constructs: you pay a penalty in
ease of understanding of the code, run-time overhead, *and* poor
optimization because the compiler can't predict control flow.
These high costs should not be built into an essential, basic control
flow construct.

regards, tom lane

Tony Garnock-Jones

unread,
Jul 10, 1994, 3:49:42 AM7/10/94
to
James Michael Chacon (j...@ksu.ksu.edu) wrote:
: c...@netcom.com (Craig Dickson) writes:
: >This person had obviously totally missed the point.

: As have you...The simple fact that is called "goto" seems to be the only
: reason you dislike it. This isn't BASIC anymore where you could just
: jump anywhere (I have seen spaghetti code in BASIC that was totally

: unitelligable this way), since the language [C] restricts it's use.

I've seen some pretty hairy examples of C code using gotos; a particular
piece of zmodem code springs immediately to mind: gotos left, right and
centre, which didn't help readability one bit :-(

Perhaps the language should restrict its use a bit more?

Tony
---
Tony Garnock-Jones (to...@kcbbs.gen.nz)

Raul Deluth Miller

unread,
Jul 10, 1994, 11:09:05 AM7/10/94
to
Raul Miller:
. |the use of C's break or continue in conjunction with the structure
. |of the code with which they must appear gives the same ultimate
. |ability as goto.

Craig Dickson:


. So you're claiming that this is somehow equivalent to a goto,

. right? It isn't. In your example, because a 'break' only occurs
. within the switch statement, it is impossible to escape the
. enclosing while loop. A goto could easily do so. Also, note that a
. 'break' from anywhere inside the switch statement can only go to
. one place: the end of the switch. Gotos are not so restricted; you
. can put the target label anywhere you like within the function.


. This is the sort of thing I mean when I say that gotos can violate

. structure, while 'break' is forced to work within structure.

[a] I was talking about the use of break in conjunction with other
features of the language. To escape the while loop, change the
while(1) to while(line!=___). Not easy enough?

[b] I don't have a copy of the C standard handy, but I was under the
distinct impression that goto will not necessarily take you anywhere
you like within the function. For example:

goto a; for (;;) {int i=0; if() {a:...;} else {b:...;}}

If goto can do this, there are implications I need to consider before
posting further on this subject.

Raul Miller:
. |And this property isn't all that C specific either. 'case' may be
. |considered to be syntactic sugar for 'else if'.

Craig Dickson:
. In contrast, while switch statements are often compiled as a series
. of if/else operations, they need not be. Many compilers will, under
. the right circumstances, implement cases as entries in a jump
. table.

Correct. And the same could be done for a chain of 'else if's, under
the right circumstances [e.g. (a) all tests compare the same variable,
for equality against a constant, and (b) enough tests to be worth
bothering with a jump table].

Miguel Carrasquer

unread,
Jul 10, 1994, 11:49:26 AM7/10/94
to
In article <ROCKWELL.94...@nova.umd.edu>,

Raul Deluth Miller <rock...@nova.umd.edu> wrote:
>
>[b] I don't have a copy of the C standard handy, but I was under the
>distinct impression that goto will not necessarily take you anywhere
>you like within the function. For example:
>
> goto a; for (;;) {int i=0; if() {a:...;} else {b:...;}}
>
>If goto can do this, there are implications I need to consider before
>posting further on this subject.
>

Sure it can. Goto in C will take you anywhere you like within the
current function.

--
Miguel Carrasquer ____________________ ~~~
Amsterdam [ ||]~
m...@inter.NL.net ce .sig n'est pas une .cig

Juergen Nickelsen

unread,
Jul 10, 1994, 12:44:23 PM7/10/94
to
In article <TGL.94Ju...@netcom5.netcom.com> t...@netcom.com (Tom
Lane) writes:

> nic...@prz.tu-berlin.de (Juergen Nickelsen) writes:
[...]


> > On the other hand, a break(n), where n is a *variable*, should enable
> > _lots_ of extremely creative uses. Sounds like a meta control
> > structure to me.
>
> That would be equivalent to a "computed goto" a la Fortran; it would
> negate every advantage of goto-less programming from both the programmer's
> and compiler's points of view, because control flow couldn't be
> determined until run-time. I don't see any value in it.

Sorry, I didn't know I'd have to put in a :-) for you. After all, *I*
read this thread in alt.folklore.computers. Read "creative" here as in
Ed Post's "Real Programmers ..." article.

--
Juergen Nickelsen

Dave Brown

unread,
Jul 10, 1994, 3:53:21 PM7/10/94
to
In article <10494190.2...@kcbbs.gen.nz>, Tony Garnock-Jones <to...@kcbbs.gen.nz> wrote:
>I've seen some pretty hairy examples of C code using gotos; a particular
>piece of zmodem code springs immediately to mind: gotos left, right and
>centre, which didn't help readability one bit :-(
>
>Perhaps the language should restrict its use a bit more?

No, perhaps the *programmers* should restrict its use a bit more. I
don't mind a goto so long as it's impossible to replace it with
anything else (that exiting multiple loops at a time is one example,
implementing highly local exceptions is another, but I can't think of
any more right now).

Dave's First Law of Computer Languages: Every 'goto' can be replaced
with some other contrived 'structured' construct.

--
Dave Brown -- dagb...@uwaterloo.ca -- (519) 725-5978
Many of them also which used curious arts brought their books together
and burned them .... So mightily grew the word of God and prevailed.
-Acts 19:19-20

Craig Dickson

unread,
Jul 10, 1994, 5:51:01 PM7/10/94
to
In article <ROCKWELL.94...@nova.umd.edu>,

Raul Deluth Miller <rock...@nova.umd.edu> wrote:

| I don't have a copy of the C standard handy, but I was under the
|distinct impression that goto will not necessarily take you anywhere
|you like within the function. For example:

I'm going to reformat your example for readability...

| goto a;
| for (;;) {
| int i=0;
| if() {
| a:
| ...;
| } else {
| b:
| ...;
| }
| }
|
|If goto can do this, there are implications I need to consider before
|posting further on this subject.

Yes, I believe the ANSI C standard will allow a goto to do that.

Matt Welsh

unread,
Jul 10, 1994, 8:42:39 PM7/10/94
to
In article <2vnk1g$19...@whale.st.usm.edu> cham...@whale.st.usm.edu (John William Chambless) writes:
> if(blargfart(err_status))
> goto BAILOUT; /* !considered(harmful) */

Of course, there's always the situation where use of goto is actually
useful for performance reasons. Take this snippet from the Linux kernel
sources (kernel/sched.c):

[...]
/*
* The "confuse_gcc" goto is used only to get better assembly code..
* Djikstra probably hates me.
*/
asmlinkage void schedule(void)
{
[...]
p = &init_task;
for (;;) {
if ((p = p->next_task) == &init_task)
goto confuse_gcc1;
[...]


confuse_gcc1:

/* this is the scheduler proper: */

[...]
c = -1;
next = p = &init_task;
for (;;) {
if ((p = p->next_task) == &init_task)
goto confuse_gcc2;

[...]

and so forth. Reorganizing this to make it "more readable" would certainly
impede performance.

M. Welsh

Phillip Burgess

unread,
Jul 11, 1994, 1:12:15 AM7/11/94
to
dagb...@undergrad.math.uwaterloo.ca (Dave Brown) writes:

>No, perhaps the *programmers* should restrict its use a bit more. I
>don't mind a goto so long as it's impossible to replace it with
>anything else (that exiting multiple loops at a time is one example,
>implementing highly local exceptions is another, but I can't think of
>any more right now).

If everything were pure and good, I would probably use gotos from time to
time in those few situations where it might help performance or readability.
However, all the Worst Code I've Ever Seen has contained gotos. It doesn't
even matter if they're what's messing up the code - the correlation
between gotos and imbecilic programmers is so strong that I just avoid
them altogether for fear that I might catch cooties. I've come to believe
that there's a finite number of gotos in the universe, and once they're all
used up, that's the end of it all. :-)

(Come to think of it, all that bad code usually contained "for" statements,
and "main" functions, and curly braces, and semicolons, and...) AAAAAHH!

Is there a Hall of Shame for particularly horriffic code? Not obfuscated,
just incredibly dense. The stories I could tell of former co-workers...

--
Phillip Burgess (pbur...@netcom.com)

Alan Watson

unread,
Jul 10, 1994, 1:42:09 PM7/10/94
to
In article <10494190.2...@kcbbs.gen.nz>

to...@kcbbs.gen.nz (Tony Garnock-Jones) wrote:
>I've seen some pretty hairy examples of C code using gotos; a particular
>piece of zmodem code springs immediately to mind: gotos left, right and
>centre, which didn't help readability one bit :-(
>
>Perhaps the language should restrict its use a bit more?

Gotos don't create unmaintainable code; programmers do.

[For those lucky people outside of the US: the National Rifle
Association claims that `Guns don't kill people; criminals do'.]

--
Alan Watson | These commands can be run only by the
al...@oldp.astro.wisc.edu | super-user, who, it is hoped, knows what
Department of Astronomy | he or she is doing.
University of Wisconsin -- Madison | -- pre-SVR3.1 man page for unlink

Paul Guertin

unread,
Jul 11, 1994, 2:34:50 AM7/11/94
to
In article <crdCso...@netcom.com>,

c...@netcom.com (Craig Dickson) writes:
>In article <CsnFw...@iro.umontreal.ca>,
>Paul Guertin <guer...@IRO.UMontreal.CA> wrote:
>
>|If you feel so strongly about gotos used to exit loops, you shouldn't
>|use break and continue statements in loops, since they are merely gotos
>|in disguise.
>
>Rubbish. A break or continue statement totally lacks the characteristic
>that makes the goto statement dangerous: the ability to go *anywhere*,
>without any reference to the structure of the code. In contrast, break
>and continue are quite limited in capability, and by definition forced
>to work within the structure of the code rather than violating it.

Reread the paragraph you quoted: I'm talking specifically about
gotos *used to exit loops*. They too are "by definition forced to work
within the structure of the code".

When the target of the goto is close enough, a simple comment like
goto empty_spot_found; /* break out of search loops */
is enough to adequately document the goto and state its innocuity.
If the target is far enough (it seldom occurs if functions are kept
small), it might be a good idea to add a comment next to the label
itself stating where control might come from.

>I recall one impressively
>dimwitted essay in one of the hobbyist magazines around ten years ago
>that argued that there's nothing wrong with goto's because your nice,
>structured HLL code, when compiled, is full of JMP instructions anyway.
>This person had obviously totally missed the point.

Agreed.

Paul Guertin
guer...@iro.umontreal.ca

Markus Freericks

unread,
Jul 11, 1994, 5:05:49 AM7/11/94
to
In article <1994Jul10....@sal.wisc.edu> al...@sal.wisc.edu (Alan Watson) writes:
> to...@kcbbs.gen.nz (Tony Garnock-Jones) wrote:
> >I've seen some pretty hairy examples of C code using gotos; a particular
> >piece of zmodem code springs immediately to mind: gotos left, right and
> >centre, which didn't help readability one bit :-(
> >
> >Perhaps the language should restrict its use a bit more?
>
> Gotos don't create unmaintainable code; programmers do.
>
> [For those lucky people outside of the US: the National Rifle
> Association claims that `Guns don't kill people; criminals do'.]

I like the reply "Guns don't kill people; ammunition does" ;-)

One point that I have not yet seen considered in this discussion is the
following one: there are two well-known languages that depend heavily on
GOTO-mediated control flow. These are FORTRAN and BASIC. Both languages did
only provide _numeric labels_ (i.e., line numbers) as destinations for GOTO
statements (at least in their early definitions). How much of the
spaghetti-ness of Fortran-66 and BASIC programs is due to the confusion
caused by this restriction to non-symbolic labels?

Markus

--
Markus Freericks m...@cs.tu-berlin.de +49-30-314-21390
TU Berlin Sekr. FR 2-2, Franklinstr. 28/29, D-10587 Berlin (Germany)
"Inertia makes the world go 'round."

Paul Guertin

unread,
Jul 11, 1994, 2:48:05 AM7/11/94
to
In article <NICKEL.94...@toftum.prz.tu-berlin.de>,

nic...@prz.tu-berlin.de writes:
>In article <CsnFw...@IRO.UMontreal.CA> guer...@IRO.UMontreal.CA
>(Paul Guertin) writes:
>
>> I think that if C provided a break(n) statement to get out of the
>> n innermost loops, the goto statement would become superfluous.
>> But it doesn't, and we have to make do with what we have.
>
>IMHO a break(n) would not be optimal in terms of readability and
>maintainability of the code. I'd rather favour a "break <label>" to
>break out of a loop construct <label>. This is in fact a goto in
>disguise (although no more than a break(n)), but in this restricted
>form it shouldn't be too bad.

IMHO, you're right.

>On the other hand, a break(n), where n is a *variable*, should enable
>_lots_ of extremely creative uses. Sounds like a meta control
>structure to me. Probably the IOCCC would benefit a lot from that.

Ouch. Why not throw in numeric labels and an arithmetic goto,
while we're at it? :-)

Paul Guertin
guer...@iro.umontreal.ca

Dolf Grunbauer

unread,
Jul 11, 1994, 6:48:20 AM7/11/94
to
What about a tool like (Obfuscated C Coding Contest 1987):
---------------------- hines.hint -------------------------------------
Worst Style: <grebyn!avalon> Spencer Hines

Spencer Hines
OnLine Computer Systems
4200 Farragut Street
Hyattsville, MD
20781
USA

Try: avalon avalon.c

This program was designed to maximize the bother function for
structured programmers. This program takes goto statements to their
logical conclusion. The layout and choice of names are classic.

We consider this to be a beautiful counter-example for Frank Rubin's
letter to ACM form titled: `` "GOTO Considered Harmful" Considered Harmful ''.
See the Communications of the ACM, March 1987, Page 195-196.
---------------------- hines.hint -------------------------------------
---------------------- hines.c ----------------------------------------
#include <stdio.h>
#include <malloc.h>
main(togo,toog)
int togo;
char *toog[];
{char *ogto, tgoo[80];FILE *ogot; int oogt=0, ootg, otog=79,
ottg=1;if ( togo== ottg) goto gogo; goto goog; ggot:
if ( fgets( tgoo, otog, ogot)) goto gtgo; goto gott;
gtot: exit(); ogtg: ++oogt; goto ogoo; togg: if ( ootg > 0)
goto oggt; goto ggot; ogog: if ( !ogot) goto gogo;
goto ggto; gtto: printf( "%d goto \'s\n", oogt); goto
gtot; oggt: if ( !memcmp( ogto, "goto", 4)) goto otgg;
goto gooo; gogo: exit( ottg); tggo: ootg= strlen(tgoo);
goto tgog; oogo: --ootg; goto togg; gooo: ++ogto; goto
oogo; gott: fclose( ogot); goto gtto; otgg: ogto= ogto +3;
goto ogtg; tgog: ootg-=4;goto togg; gtgo: ogto= tgoo;
goto tggo; ogoo: ootg-=3;goto gooo; goog: ogot= fopen(
toog[ ottg], "r"); goto ogog; ggto: ogto= tgoo; goto
ggot;}
---------------------- hines.c ----------------------------------------
--
_ _
/ U | Dolf Grunbauer WorkGroup Applications: CasePlan/LinkWorks for Windows
/__'< Digital Equipment Corporation, PObox 245, Apeldoorn, The Netherlands
88 |_\ DTN:829-4037 Email: do...@apd.dec.com

Mark Hughes

unread,
Jul 11, 1994, 7:39:53 AM7/11/94
to
On 11 Jul 1994 09:05:49 GMT, Markus Freericks (m...@cs.tu-berlin.de) is alleged to have written:
: One point that I have not yet seen considered in this discussion is the

: following one: there are two well-known languages that depend heavily on
: GOTO-mediated control flow. These are FORTRAN and BASIC. Both languages did
: only provide _numeric labels_ (i.e., line numbers) as destinations for GOTO
: statements (at least in their early definitions). How much of the
: spaghetti-ness of Fortran-66 and BASIC programs is due to the confusion
: caused by this restriction to non-symbolic labels?

Well, back when I programmed in Atari Basic (and I wrote structured programs
with only stone knives and bear..., er, with only goto, if, and for), I
discovered that variable references were faster than constants, so I used the
calculated goto and named all important line numbers with variables at the start
of the program:

1 GOTO 32000
9 ' UPDATE_DISPLAY
10 ...
99 ' MAIN_LOOP
100 ...
165 GOSUB UPDATE_DISPLAY: GOTO MAIN_LOOP
31999 ' INITIALIZE
32000 MAIN_LOOP=100: UPDATE_DISPLAY=10
32001 GOTO MAIN_LOOP

It worked great, as long as I NEVER EVER renumbered the program. (The strange
order is caused by Atari Basic's brain-damaged way of searching for line numbers
- searching through a linked list).

I've never understood gotophobia... If it's a useful tool, I'll use it. If
some gotophobic fascist makes a language without a goto, I'll either fix the
language or not use it.

-Mark Hughes
"FORTRAN's DO statement is far scarier than GOTO ever was - nothing can match
the sheer gibbering horror of the `come from' loop if the programmer didn't
document it well..."

David Hanley

unread,
Jul 11, 1994, 11:17:17 AM7/11/94
to

: Is there a Hall of Shame for particularly horriffic code? Not obfuscated,

: just incredibly dense. The stories I could tell of former co-workers...

Have you looked at the code for the public domain spreadsheet
xspread?

--
|------------------------------------------------------------------------|B
|David James Hanley | The devil is only a convenient myth |
|"The Cockroach" | invented by the real malefactors |O
|dha...@lac.eecs.uic.edu | of our world. |
|Laboratory for advanced computing| -Robert Anton Wilson |B
|-------------------------------------------------------------------------
My employer doesn't even agree with me about C indentation style.
------------------> I.N.R.I : I Never Risk Inquiry <-----------------

Craig Dickson

unread,
Jul 11, 1994, 11:50:02 AM7/11/94
to
In article <2vqugc$s...@news.cs.tu-berlin.de>,
Markus Freericks <m...@cs.tu-berlin.de> wrote:

|One point that I have not yet seen considered in this discussion is the
|following one: there are two well-known languages that depend heavily on
|GOTO-mediated control flow. These are FORTRAN and BASIC. Both languages did
|only provide _numeric labels_ (i.e., line numbers) as destinations for GOTO
|statements (at least in their early definitions). How much of the
|spaghetti-ness of Fortran-66 and BASIC programs is due to the confusion
|caused by this restriction to non-symbolic labels?

I suppose that makes it somewhat worse, but I don't think the numeric
labels as really that big a deal; one can always comment. The real
problem for maintainability is when you have trouble figuring out
everything that's going on because the flow of control is jumping
around like hot oil on a griddle.

Scott E Gilbert

unread,
Jul 11, 1994, 12:56:44 PM7/11/94
to
>---------------------- hines.c ----------------------------------------
#include <stdio.h>
#include <malloc.h>
main(togo,toog)
int togo;
char *toog[];
{char *ogto, tgoo[80];FILE *ogot; int oogt=0, ootg, otog=79,
ottg=1;if ( togo== ottg) goto gogo; goto goog; ggot:
if ( fgets( tgoo, otog, ogot)) goto gtgo; goto gott;
gtot: exit(); ogtg: ++oogt; goto ogoo; togg: if ( ootg > 0)
goto oggt; goto ggot; ogog: if ( !ogot) goto gogo;
goto ggto; gtto: printf( "%d goto \'s\n", oogt); goto
gtot; oggt: if ( !memcmp( ogto, "goto", 4)) goto otgg;
goto gooo; gogo: exit( ottg); tggo: ootg= strlen(tgoo);
goto tgog; oogo: --ootg; goto togg; gooo: ++ogto; goto
oogo; gott: fclose( ogot); goto gtto; otgg: ogto= ogto +3;
goto ogtg; tgog: ootg-=4;goto togg; gtgo: ogto= tgoo;
goto tggo; ogoo: ootg-=3;goto gooo; goog: ogot= fopen(
toog[ ottg], "r"); goto ogog; ggto: ogto= tgoo; goto
ggot;}
>---------------------- hines.c ----------------------------------------

Ok, I'll bite. I compiled it and renamed it goto, but still can't figure
out exactly what its supposed to do... So what's it supposed to do?

(Besides irritate the anal amongst us of course...)

--
\\======= Scott Gilbert ========\\
\\ sc...@caslon.cs.arizona.edu \\
\\ sc...@gas.uug.arizona.edu \\
\\==============================\\

Dave Brown

unread,
Jul 11, 1994, 1:02:45 PM7/11/94
to
In article <CsrK8...@iro.umontreal.ca>, Paul Guertin <guer...@IRO.UMontreal.CA> wrote:
>>On the other hand, a break(n), where n is a *variable*, should enable
>>_lots_ of extremely creative uses. Sounds like a meta control
>>structure to me. Probably the IOCCC would benefit a lot from that.
>
>Ouch. Why not throw in numeric labels and an arithmetic goto,
>while we're at it? :-)

No. An arithmetic COME FROM, of course!!!

:-)

Seen in a Hong Kong supermarket: For your convenience, we recommend
courteous, efficient self-service.

Raul Deluth Miller

unread,
Jul 11, 1994, 1:44:16 PM7/11/94
to
Alan Watson:
. > Gotos don't create unmaintainable code; programmers do.
. >
. > [For those lucky people outside of the US: the National Rifle
. > Association claims that `Guns don't kill people; criminals do'.]

Markus Freericks:


. I like the reply "Guns don't kill people; ammunition does" ;-)

I like to point out that cars are more dangerous, and bad eating
habits are even worse in terms of number of people killed. [Surgery
isn't particularly safe either.]

. One point that I have not yet seen considered in this discussion is
. the following one: there are two well-known languages that depend
. heavily on GOTO-mediated control flow. These are FORTRAN and
. BASIC. Both languages did only provide _numeric labels_ (i.e., line
. numbers) as destinations for GOTO statements (at least in their
. early definitions).

APL comes pretty close to being in this category as well. It has line
labels, but they're numerical things -- the line lable for line 9
would be a symbol whose value is 9. Of course, APL doesn't really
need to use anything other than straight through control flow unless
it's dealing with I/O. And, it could be argued that FSMs is the best
mechanism for dealing with I/O. [And, APL's design makes it easy to
put line labels in tables, if that's what's desired.]

Nevin Liber

unread,
Jul 11, 1994, 3:25:14 PM7/11/94
to
In article <2vnk1g$19...@whale.st.usm.edu>,

John William Chambless <cham...@whale.st.usm.edu> wrote:

>My personal prejudice (isn't that what this discussion REALLY is about?)
>is that if a GOTO makes the code clear, and the label is VERY close to
>the GOTO (in the same screenful) it's okay.

That's fine for school projects and one-shot programs. However, as someone
who has had to maintain and modify existing code bases, it's impossible to
guarantee that the label will remain very close to the GOTO forever.
Plus, depending on where in the development or maintenance cycle you
are, you might not be allowed the risk of rewriting the code to get rid
of the GOTO.

Just wondering: is there a case (hopefully not too contrived) where
the label is very close to the GOTO, yet using a looping construct and
a break to replace it would be much worse?

I've been programming in C for a number of years now, and I've never
found a need to use a GOTO. I still have an open mind about it; I just
haven't seen any compelling reason to use it.
--
Nevin ":-)" Liber ne...@cs.arizona.edu (602) 293-2799
+++ (520) after 3/95
summer office: (602) 621-8112
Only 32 more shopping days 'til my birthday (August 12th)!!

Nevin Liber

unread,
Jul 11, 1994, 3:39:25 PM7/11/94
to
In article <1994Jul11.0...@cs.cornell.edu>,
Matt Welsh <m...@cs.cornell.edu> wrote:

>Of course, there's always the situation where use of goto is actually
>useful for performance reasons.

Very rare. Especially since it isn't something compiler writers
typically concentrate on when doing their optimisers.

Why is the above code any better than (only rewriting the gotos as while
loops):

asmlinkage void schedule(void)
{
/* [...] */

p = &init_task;
while (&init_task != (p = p -> next_task)) {
/* [...] */
}

/* [...] */

/* this is the scheduler proper: */

c = -1;


next = p = &init_task;

while (&init_task != (p = p -> next_task)) {
/* [...] */
}

/* [...] */

Edward L. Karrels

unread,
Jul 11, 1994, 6:08:18 PM7/11/94
to
In article <2vs6aq$7...@caslon.CS.Arizona.EDU> ne...@CS.Arizona.EDU (Nevin Liber) writes:


Just wondering: is there a case (hopefully not too contrived) where
the label is very close to the GOTO, yet using a looping construct and
a break to replace it would be much worse?

I am normally a non-goto person, but in a recent case I used a few goto's
to hopefully optimize a section of code. It involoved a series of for
loops. At each iteration, a check must me made. If the check is false
once, it is not necessary to perform the check again:

(abbreviated)

for (x) {
Stuff();
if (DoCheck()) goto lbl1;
}
for (y) {
Stuff();
if (DoCheck()) goto lbl2;
}

return 1;

for (x) {
Stuff();
lbl1:
}
for (y) {
Stuff();
lbl2:
}

return 0;

I think if I tried to do this in a more structured fashion, it would lose
the cleanliness of this approach.

Ed

Wilson Roberto Afonso

unread,
Jul 11, 1994, 8:35:12 PM7/11/94
to
pbur...@netcom.com (Phillip Burgess) writes:
>I've come to believe
>that there's a finite number of gotos in the universe, and once they're all
>used up, that's the end of it all. :-)

So that's what is going to happen at midnight, Jan. 1 2001 ? Some lazy
programmer will put the last "goto" in place and...

-Wilson (used gotos in Pascal out of dire need and hurry)

--
Wilson Roberto Afonso NA Nutec Corporation
+1 415 988-9781 2685 Marine Way Suite 1319
FAX: +1 415 988-9782 Mountain View, CA 94043
Internet: wil...@nutec.com

Craig Dickson

unread,
Jul 12, 1994, 1:38:47 AM7/12/94
to
In article <KARRELS.94...@elf.mcs.anl.gov>,

Edward L. Karrels <kar...@mcs.anl.gov> wrote:

|I am normally a non-goto person, but in a recent case I used a few goto's
|to hopefully optimize a section of code. It involoved a series of for
|loops. At each iteration, a check must me made.

Did you look at the resulting object code to see if it helped?

| If the check is false
|once, it is not necessary to perform the check again:
|
| (abbreviated)
|
| for (x) {
| Stuff();
| if (DoCheck()) goto lbl1;
| }
| for (y) {
| Stuff();
| if (DoCheck()) goto lbl2;
| }
|
| return 1;
|
| for (x) {
| Stuff();
| lbl1:
| }
| for (y) {
| Stuff();
| lbl2:
| }
|
| return 0;
|
|I think if I tried to do this in a more structured fashion, it would lose
|the cleanliness of this approach.

You call jumping from the middle of one for loop to the middle of another
one "clean"? Yow!

I don't know how much you needed *every* *last* *bit* *of* *speed* in this
code, but the following is far less noxious and very nearly as fast, since
the call to DoCheck() is conditional on DoCheck() never having returned 1.
This code should also be smaller than yours, since it has only two for
loops rather than four.

int callDoCheck = 1;

for (x) {
Stuff();
if (callDoCheck)
callDoCheck = !DoCheck();
}
}

for (y) {
Stuff();
if (callDoCheck)
callDoCheck = !DoCheck();
}
}

return callDoCheck;

John William Chambless

unread,
Jul 12, 1994, 8:31:50 AM7/12/94
to
In article <1994Jul10....@sal.wisc.edu>,
Alan Watson <al...@sal.wisc.edu> wrote:

>Gotos don't create unmaintainable code; programmers do.

Dykstra can have my GOTO when he pries it from my cold,
dead workstation.


--
* Billy Chambless University of Southern Mississippi
* Clinton gets elected; Frank Zappa and Richard Nixon die. Coincidence?

Roger Barnett

unread,
Jul 12, 1994, 5:34:38 AM7/12/94
to
In article <CsrK8...@IRO.UMontreal.CA>
guer...@IRO.UMontreal.CA "Paul Guertin" writes:

> In article <NICKEL.94...@toftum.prz.tu-berlin.de>,
> nic...@prz.tu-berlin.de writes:
> >In article <CsnFw...@IRO.UMontreal.CA> guer...@IRO.UMontreal.CA
> >(Paul Guertin) writes:
> >
> >> I think that if C provided a break(n) statement to get out of the
> >> n innermost loops, the goto statement would become superfluous.
> >> But it doesn't, and we have to make do with what we have.
> >

> [snip]


> >
> >On the other hand, a break(n), where n is a *variable*, should enable
> >_lots_ of extremely creative uses. Sounds like a meta control
> >structure to me. Probably the IOCCC would benefit a lot from that.
>
> Ouch. Why not throw in numeric labels and an arithmetic goto,
> while we're at it? :-)
>

Then there was the "return n" statement in a Nixdorf Basic which returned
from a subroutine to the nth line after (n>0) or before (n<0) the calling
statement...

Seems to me that the anti-gotos in this thread talk about routines full of
goto statements jumping all over the place, while the non-anti-gotos talk
about routines with one or two at most used in some kind of controlled way
- hey guys, I don't think you're going to reach agreement here !

FWIW I use several 3GLs on a regular basis which contain various levels of
support for control structures, so I can't afford to have a blanket prejudice
on this. However, I do find the C "continue" (and "break" in loops to a lesser
extent) a bit of a pain when trying to maintain code which often contains
nested loops containing a couple of hundred lines plus. Still, the most
obscure code I've seen (apart from the Basic mentioned above) was written
in Algol 68 - no gotos but a hell of a thing to follow. All IMHO natch.

--
Roger Barnett
"There are helicopters on the walls of Troy"
Clive James

Jim Frost

unread,
Jul 12, 1994, 11:22:44 AM7/12/94
to
guer...@IRO.UMontreal.CA (Paul Guertin) writes:
>I think that if C provided a break(n) statement to get out of the
>n innermost loops, the goto statement would become superfluous.
>But it doesn't, and we have to make do with what we have.

While I agree that multilevel break would be very useful, I'd still
use a goto in many cases because it would get very difficult to tell
where the exit point is. A label makes it very obvious.

jim frost
ji...@centerline.com

Jim Frost

unread,
Jul 12, 1994, 11:34:43 AM7/12/94
to
c...@netcom.com (Craig Dickson) writes:
>In contrast, while switch statements are often compiled as a series of
>if/else operations, they need not be. Many compilers will, under the
>right circumstances, implement cases as entries in a jump table. This
>can improve performance and reduce the size of the compiled code.

I've even seen compilers build them into decision trees. Clearly the
switch statement leaves the compiler's options open.

>Also,
>one case can fall through to another, which would be impossible to
>express using cascaded if/else syntax.

This is not really true:

if (foo) {
/* ... */
}
else if (bar) {
/* ... */
goto else_clause;
}
else {
else_clause:
/* ... */
}

While I would never, ever, EVER write that kind of code you'll find
that it's legal (and disgusting :-).

I wouldn't have ever written something like that, and would have sworn
it was illegal, but I ran into "production" code with similar
constructs written by a man whom I believe to be insane. He basically
wrote:

switch (foo) {
case 1:
if (bar) {
case 2:
/* ... */
}
}

I would never have tried that in a million years and was totally
amazed that it was accepted by every compiler I fed it to.

(This same man wrote a single C statement comprised of ?: statements
nested forty deep and I don't even remember how many long, rife with
side-effects. Truly a dizzying intellect.)

jim frost
ji...@centerline.com

Jim Frost

unread,
Jul 12, 1994, 11:43:54 AM7/12/94
to
rock...@nova.umd.edu (Raul Deluth Miller) writes:
>[b] I don't have a copy of the C standard handy, but I was under the

>distinct impression that goto will not necessarily take you anywhere
>you like within the function. For example:

> goto a; for (;;) {int i=0; if() {a:...;} else {b:...;}}

>If goto can do this, there are implications I need to consider before
>posting further on this subject.

It can, although it's illegal in C++ because of the initializer
(remove the i=0 and it is legal there, too). The use of gotos in this
manner is something I have seen in "real" code and which I am
adamantly against.

You learn something new every day, eh?

jim frost
ji...@centerline.com

Matt Welsh

unread,
Jul 12, 1994, 11:27:36 AM7/12/94
to
In article <2vs75d$7...@caslon.CS.Arizona.EDU> ne...@CS.Arizona.EDU (Nevin Liber) writes:
>
>Why is the above code any better than (only rewriting the gotos as while
>loops):

Because I deleted a lot of intervening code. The gotos were present in
multiply-nested loops.

> Only 32 more shopping days 'til my birthday (August 12th)!!

I'll keep that in mind. Are you sure that you don't want another Wet-Vac
this year?

M. Welsh

Bob Zwarick

unread,
Jul 12, 1994, 1:40:36 PM7/12/94
to
Personally, I prefer the ComeFrom instruction anyday. That way, all 'references' are centralized at
the 'target'.
----
R. M. Zwarick
------------------------------------------------------------
"One cannot, as a matter of principle, know the present in all it's detail."
------------------------------------------------------------


Ed Taft

unread,
Jul 12, 1994, 12:40:29 PM7/12/94
to
ji...@centerline.com (Jim Frost) writes:
>
> switch (foo) {
> case 1:
> if (bar) {
> case 2:
> /* ... */
> }
> }

Reminds me of this gem from _C: A Reference Manual_ by Harbison & Steele:

switch (x)
default:
if (prime(x))
case 2: case 3: case 5: case 7:
process_prime(x);
else
case 4: case 6: case 8: case 9: case 10:
process_composite(x);

They go on to say: "This is, frankly, the most bizarre switch
statement we have ever seen that still has pretenses to being
purposeful."
--
Ed Taft ta...@adobe.com

Message has been deleted

Hans Mulder

unread,
Jul 12, 1994, 3:35:46 PM7/12/94
to
In <1994Jul11.0...@cs.cornell.edu> m...@cs.cornell.edu (Matt Welsh) writes:

>In article <2vnk1g$19...@whale.st.usm.edu> cham...@whale.st.usm.edu (John William Chambless) writes:
>> if(blargfart(err_status))
>> goto BAILOUT; /* !considered(harmful) */

>Of course, there's always the situation where use of goto is actually
>useful for performance reasons.

Unlikely: optimizers tend to be confused by the sort of structure that a
goto produces, unless it's something harmless like a break(2); in disguise.

>Take this snippet from the Linux kernel
>sources (kernel/sched.c):

>[...]
>/*
> * The "confuse_gcc" goto is used only to get better assembly code..
> * Djikstra probably hates me.
> */

... especially since you're misspelling his name. He's called Dijkstra.

--
HansM ha...@win.tue.nl

The question of whether a computer can think is no more interesting than
the question of whether a submarine can swim. -- Edsger W. Dijkstra

Craig Dickson

unread,
Jul 12, 1994, 5:46:46 PM7/12/94
to
In article <2vud6j$5...@wcap.centerline.com>,
Jim Frost <ji...@centerline.com> wrote:

|c...@netcom.com (Craig Dickson) writes:
|>Also,
|>one case can fall through to another, which would be impossible to
|>express using cascaded if/else syntax.
|
|This is not really true:
|
| if (foo) {
| /* ... */
| }
| else if (bar) {
| /* ... */
| goto else_clause;
| }
| else {
| else_clause:
| /* ... */
| }

The fact that you can do it by adding a goto is irrelevant to the fact
that the if/else syntax itself is not completely equivalent to a switch
statement, which was what someone else claimed ("'case' is just syntactic
sugar for 'else if'", clearly an incorrect assertion).

Craig Dickson

unread,
Jul 12, 1994, 5:53:11 PM7/12/94
to
In article <2vucg4$4...@wcap.centerline.com>,
Jim Frost <ji...@centerline.com> wrote:

|While I agree that multilevel break would be very useful, I'd still
|use a goto in many cases because it would get very difficult to tell
|where the exit point is. A label makes it very obvious.

What isn't obvious, though, is how many other places in the function
jump to that same label. In a small function this doesn't cause a big
prblem, but in large functions it becomes extremely annoying.

dave...@news.delphi.com

unread,
Jul 12, 1994, 7:35:04 PM7/12/94
to
kar...@mcs.anl.gov (Edward L. Karrels) writes:

>In article <2vs6aq$7...@caslon.CS.Arizona.EDU> ne...@CS.Arizona.EDU (Nevin Liber) writes:


> Just wondering: is there a case (hopefully not too contrived) where
> the label is very close to the GOTO, yet using a looping construct and
> a break to replace it would be much worse?

Well, there's always the case where you want to break out of a loop as
the action for a case clause in a switch statement. In this situation,
a goto is the best choice, because break won't take you out of the loop.

(This happened to me once)

Buddha Buck

unread,
Jul 12, 1994, 10:59:54 PM7/12/94
to
In article <1994Jul12.1...@adobe.com>,

Ed Taft <ta...@mv.us.adobe.com> wrote:
>Reminds me of this gem from _C: A Reference Manual_ by Harbison & Steele:
>
> switch (x)
> default:
> if (prime(x))
> case 2: case 3: case 5: case 7:
> process_prime(x);

/* Somebody tell me why there is no break here? */

> else
> case 4: case 6: case 8: case 9: case 10:
> process_composite(x);
>
>They go on to say: "This is, frankly, the most bizarre switch
>statement we have ever seen that still has pretenses to being
>purposeful."

It seems to me that it would process 7 as both prime and composite.

Why not?

>--
>Ed Taft ta...@adobe.com


--
bb...@nox.cs.du.edu # http://nyx10.cs.du.edu:8001/~bbuck/home.html
Buddha Buck #
85.5 Albany Street # The above opinions are mine, MINE, MINE!!!
Cazenovia, NY 13035 # and you can't have them! So there!

Mandeep S Dhami

unread,
Jul 12, 1994, 11:37:29 PM7/12/94
to
In ro...@belvedere.sbay.org (David E. Fox) writes:

>Scott E Gilbert (sc...@CS.Arizona.EDU) wrote:
>:
>: Ok, I'll bite. I compiled it and renamed it goto, but still can't figure


>: out exactly what its supposed to do... So what's it supposed to do?
>

>It counts the number of gotos in a C program.
>

It actually counts all occurences of string "goto" in file name arg 1. So
for example a file with "gototogotogogoto" produces 3 goto's.

Boy, we must be crazy even trying to read it. :)

Mandeep

Lennart Benschop

unread,
Jul 13, 1994, 5:14:41 AM7/13/94
to
In article <2vvlba$s...@nyx10.cs.du.edu>,
Buddha Buck <bb...@nyx10.cs.du.edu> wrote:
-In article <1994Jul12.1...@adobe.com>,
-Ed Taft <ta...@mv.us.adobe.com> wrote:
->Reminds me of this gem from _C: A Reference Manual_ by Harbison & Steele:
->
-> switch (x)
-> default:
-> if (prime(x))
-> case 2: case 3: case 5: case 7:
-> process_prime(x);
-
-/* Somebody tell me why there is no break here? */
->
-> else
-> case 4: case 6: case 8: case 9: case 10:
-> process_composite(x);
->
->They go on to say: "This is, frankly, the most bizarre switch
->statement we have ever seen that still has pretenses to being
->purposeful."
-
-It seems to me that it would process 7 as both prime and composite.
-
-Why not?
Must get my ANSI standard document for that, but it does not process
7 as both prime and composite. I can also see why, but the nice ANSI
document is definitely more porecise on it. (semantics of gotos or
switch to case labels into an if statement). Just see case labels as a
special kind of labels.

The switch statement jumps to case 7, which is inside the if-part of the
if-statement. If the code of the if-part of an if-statement is executed,
then the code of the else-part is skipped. Typically the compiler would
insert a JUMP instruction after the code of the if-part that jumps
beyond the else part.

if(foo) {bar();} else {baz();}

if more or less equivalent to

if(!foo)goto lab1; bar(); goto lab2; lab1: baz(); lab2:

Now if you have an extraa label in front of bar() and jumpt to it, you
wouldn't execute baz(), wouldn't you?

There isn't a problem with the semantics of gotos into a for-loop either;

for(i=0;i<10;i++)foo();

is more or less equivalent to

i=0;while(i<10){foo();i++;}

which in turn is more or less equivalent to

i=0; goto lab2; lab1: foo(); i++; lab2: if(x<10)goto lab1;

Now add yet another label to the mess and goto it. I might be undefined, but
it needn't be. Every aspect of the behaviour is completely clear.
--
Lennart Benschop --- len...@stack.urc.tue.nl
"Real programmers do it in hacks."
52 65 61 6C 20 70 72 6F 67 72 61 6D 6D 65 72 73 20 64 6F 20 69 74 20
69 6E 20 68 61 63 6B 73 2E Forth/C/6809/Linux/ZX-Spectrum/Z80/80x86

Dolf Grunbauer

unread,
Jul 13, 1994, 7:06:06 AM7/13/94
to
Ro...@natron.demon.co.uk (Roger Barnett) writes:

>nested loops containing a couple of hundred lines plus. Still, the most
>obscure code I've seen (apart from the Basic mentioned above) was written
>in Algol 68 - no gotos but a hell of a thing to follow. All IMHO natch.

In Algol-68 it is not necessary to write the word GOTO at all, just use
the label, for example:

GOTO label;
<code>
label:<more code>

could also have been written as:

label;
<code>
label:<more code>

Dolf
--
_ _
/ U | Dolf Grunbauer WorkGroup Applications: CasePlan/LinkWorks for Windows
/__'< Digital Equipment Corporation, PObox 245, Apeldoorn, The Netherlands
88 |_\ DTN:829-4037 Email: do...@apd.dec.com

iv...@cc.usu.edu

unread,
Jul 13, 1994, 11:29:38 AM7/13/94
to
In article <2vvlba$s...@nyx10.cs.du.edu>, bb...@nyx10.cs.du.edu (Buddha Buck) writes:
> In article <1994Jul12.1...@adobe.com>,
> Ed Taft <ta...@mv.us.adobe.com> wrote:
>> if (prime(x))
>> case 2: case 3: case 5: case 7:
>> process_prime(x);
>> else
>> case 4: case 6: case 8: case 9: case 10:
>> process_composite(x);
>
> It seems to me that it would process 7 as both prime and composite.
>
> Why not?

Because of the 'else'.
--
----------------+------------------------------------------------------
Roger Ivie | Don't think of it as a 'new' computer, think of it as
iv...@cc.usu.edu | 'obsolete-ready'

Theo Norvell

unread,
Jul 13, 1994, 4:13:26 PM7/13/94
to
In article <crdCsM...@netcom.com> c...@netcom.com (Craig Dickson) writes:
>
>Horror of horrors: I once knew a C programmer who implemented *all*
>his loops with goto's. He cheerfully described himself as an assembly
>language programmer forced to use a C compiler. His code was known
>to be useful in cases of food poisoning, as exposure to it generally
>induced vomiting.

While this particular programmer sounds like a very poor specimen,
one can also develop the habit of coding all loops with goto's
for good reasons.

The while loop is only specific case of recursive procedures and
it is known that the formal development of programs in terms of
the more general concept has no drawbacks and often some advantages
(see "do considered od" by Eric Hehner in Acta Informatica 1979 v11 #4).
Once you develop the right set of mental habits, the same applies to
informal program development and program comprehension. If you have a
tail-recursive procedure that is called (from outside) only once,
then the most natural way to code it in C or Pascal is to use a
label and goto(s). A classic example is the 2D array search:
(var r:=0 ;
search_from_r :
if r < N
then (var c:=0 ;
search_from_r_c :
if c < N
then if suitable( A[r,c] )
then (Stuff to do when the target is found)
else (c:=c+1 ; goto search_from_r_c )
else (r:=r+1 ; goto search_from_r) )
else (Stuff to do when the target is absent) )
It is difficult (perhaps impossible) to code this nicely without using
a goto, procedures, or extra variables.

Of course what is really wanted is a programming construct that supports
this style of development. Some Lisps have the LABEL special form, Scheme
has an extended form of LET
(LET search_from_r ((r 0)) ...) ,
the "let" expressions of Haskell and other functional languages come close
let search_from r = ... in search_from 0 ;
but most languages are lacking.

Theo Norvell

Wilson Roberto Afonso

unread,
Jul 13, 1994, 1:04:05 PM7/13/94
to
bb...@nyx10.cs.du.edu (Buddha Buck) writes:
>In article <1994Jul12.1...@adobe.com>,
>Ed Taft <ta...@mv.us.adobe.com> wrote:
>> switch (x)
>> default:
>> if (prime(x))
>> case 2: case 3: case 5: case 7:
>> process_prime(x);
>/* Somebody tell me why there is no break here? */
>> else
>> case 4: case 6: case 8: case 9: case 10:
>> process_composite(x);
>It seems to me that it would process 7 as both prime and composite.
>Why not?

Because 7 would fail the test "if(prime(x))".

-Wilson

Peter da Silva

unread,
Jul 13, 1994, 7:23:48 PM7/13/94
to
In article <2vud6j$5...@wcap.centerline.com>,

Jim Frost <ji...@centerline.com> wrote:
> I wouldn't have ever written something like that, and would have sworn
> it was illegal, but I ran into "production" code with similar
> constructs written by a man whom I believe to be insane. He basically
> wrote:

> switch (foo) {
> case 1:
> if (bar) {
> case 2:
> /* ... */
> }
> }

That's nearly as bad as Duff's Device, where you have a switch and a for
loop intermixed.
--
Peter da Silva `-_-'
Network Management Technology Incorporated 'U`
1601 Industrial Blvd. Sugar Land, TX 77478 USA
+1 713 274 5180 "Hast Du heute schon Deinen Wolf umarmt?"

Patrick D. Logan

unread,
Jul 13, 1994, 1:48:14 PM7/13/94
to
In article <2vs6aq$7...@caslon.CS.Arizona.EDU> ne...@CS.Arizona.EDU (Nevin Liber) writes:

>In article <2vnk1g$19...@whale.st.usm.edu>,
>John William Chambless <cham...@whale.st.usm.edu> wrote:

>>My personal prejudice (isn't that what this discussion REALLY is about?)
>>is that if a GOTO makes the code clear, and the label is VERY close to
>>the GOTO (in the same screenful) it's okay.

>That's fine for school projects and one-shot programs. However, as someone
>who has had to maintain and modify existing code bases, it's impossible to
>guarantee that the label will remain very close to the GOTO forever.

Now, I'm not arguing for using GOTOs, but this particular argument against
them does not hold water. If the code is going to evolve such that so much
distance is placed between the GOTO and the label then the quality of the code
is deteriorating in *general* whether or not there is a GOTO. It is in general
becoming more difficult to maintain.

If there is a proper use of a GOTO in a piece of code, and if that code is
*well* maintained, then that use of GOTO should remain "proper" by whatever
definition the developers have given "proper" to be.

If code is not going to be maintained well, then *all* bets are off. I have
seen pretty unmaintainable code that does not have any GOTOs and could even
said to be "structured" (even "object oriented")!
Patrick...@ccm.jf.intel.com
(503) 696-9309
Intel / ProShare Conferencing

Craig Dickson

unread,
Jul 14, 1994, 2:26:34 AM7/14/94
to
In article <1994Jul13.2...@client11.comlab.ox.ac.uk>,
Theo Norvell <nor...@comlab.ox.ac.uk> wrote:

Want to bet?

void ScanArray2D(<type> *A, int N)
{
int r, c;

for (r = 0; r < N; r++)
for (c = 0; c < N; c++)
if (suitable(A[r][c]))
{
// stuff to do when the target is found goes here
return;
}

// stuff to do when the target is absent goes here
}

Now, of course, I'm using a reasonable language (C), whereas your
example is in an unreasonable one (Pascal), but even so, I think
my point is made...

Simon Dawson

unread,
Jul 14, 1994, 4:19:38 AM7/14/94
to
In <2vv9b8$e...@news.delphi.com> dave...@news.delphi.com (DAVEG...@DELPHI.COM) writes:

You've got to wonder if things like Visual Basic providing Exit Sub, and Exit For
commands, (instead of gotos) are a good thing or not.. now we've got
into the habit of using them, we've found them remarkably useful..
great for speeding up code once you don't need a loop anymore..

And guaranteed as a tight, clean method of exiting..

But are we guilty?

SImon

--

Sim...@PERCEPTION.Manawatu.Gen.NZ (Simon Dawson)
----------------------------------------------------------------
Analysing the past. Creating the future. Controlling the present

Hans Mulder

unread,
Jul 14, 1994, 3:24:00 PM7/14/94
to
In <Csw22...@nutec.com> wil...@nutec.com (Wilson Roberto Afonso) writes:

>bb...@nyx10.cs.du.edu (Buddha Buck) writes:
>>In article <1994Jul12.1...@adobe.com>,
>>Ed Taft <ta...@mv.us.adobe.com> wrote:
>>> switch (x)
>>> default:
>>> if (prime(x))
>>> case 2: case 3: case 5: case 7:
>>> process_prime(x);
>>/* Somebody tell me why there is no break here? */
>>> else
>>> case 4: case 6: case 8: case 9: case 10:
>>> process_composite(x);
>>It seems to me that it would process 7 as both prime and composite.
>>Why not?

Because the "else" causes a jump across the next two lines. If you reach
an "else" statement by executing the code directly before it, you'll skip
the "else" branch. At that point, it doesn't matter whether you reached
to "then" branch by satisfying the condition of the "if" or by "goto"ing
around the "if" altogether.

>Because 7 would fail the test "if(prime(x))".

That test is never executed: control hops from the "switch" to the "case 7",
bypassing the "if (prime(x))".

--
HansM ha...@win.tue.nl

The word `language' is a misnomer. Languages are things like Dutch and English.
They are for telling jokes in and making love in. -- Edsger W. Dijkstra

Jim Frost

unread,
Jul 14, 1994, 5:18:54 PM7/14/94
to
cham...@whale.st.usm.edu (John William Chambless) writes:
>In article <1994Jul10....@sal.wisc.edu>,
>Alan Watson <al...@sal.wisc.edu> wrote:

>>Gotos don't create unmaintainable code; programmers do.

>Dykstra can have my GOTO when he pries it from my cold,
>dead workstation.

Dijkstra will always P whenever you V.

(I must have had too much caffeine today.)

jim frost
ji...@centerline.com

Wayne Throop

unread,
Jul 14, 1994, 12:00:30 PM7/14/94
to
: From: nor...@comlab.ox.ac.uk (Theo Norvell)
: (var r:=0 ;

: search_from_r :
: if r < N
: then (var c:=0 ;
: search_from_r_c :
: if c < N
: then if suitable( A[r,c] )
: then (Stuff to do when the target is found)
: else (c:=c+1 ; goto search_from_r_c )
: else (r:=r+1 ; goto search_from_r) )
: else (Stuff to do when the target is absent) )
: It is difficult (perhaps impossible) to code this nicely without using
: a goto, procedures, or extra variables.

Exqueese me? Baking Powder? Consider (eg, in C-ese):

for( r=0; r<N; r+=1 )
for( c=0; c<N; c+=1 )
if( suitable( A[r,c] ) ) {
do_stuff_when_target_found;
r=c=(N+1);
}
if( r==N )
do_stuff_when_target_absent;

Granted, it has an extra *test* on the variable r, but it has no extra
variables, the two exit variants being encoded in the existing
variables. Is it "nice"? I don't find it *un*nice... certainly, the
collection of the loop control information into a "for" instead of being
spread all about the place helps the readability for me, but of course
YMMV.

On the other hand, I'll admit I like a language with "leave via", and
specific exit clauses bound to a block of code, or a catch/throw
mechanism, such as (eg, in slightly mutant tcl-ese)

catch {
for {set r 0} r<N {inc r} {
for {set c 0} c<N {inc c} {
if [suitable($A[$r,$c])] {
do_stuff_when_target_found
throw found
} } }
do_stuff_when_target_not_found
}

or some syntactic sugar, to do exit cases

catch_exits {
for {set r 0} r<N {inc r} {
for {set c 0} c<N {inc c} {
if [suitable($A[$r,$c])] {
throw found
} } }
throw not_found
} found {
do_stuff_when_target_found
} not_found {
do_stuff_when_target_not_found
}

So why are exit clauses or catch/throw better than (or even different
than) goto? Because the scope of the control-flow jink is clearly
delimited, and because the block of code enclosed by the "catch" now has
clearly defined exit conditions, which greatly simplifies the case
analysis involved in reasoning about the requires/ensures and invariant
properties of the code. Again, YMMV.

--
Wayne Throop throopw%sh...@concert.net
thr...@aur.alcatel.com

Craig Dickson

unread,
Jul 15, 1994, 1:35:08 AM7/15/94
to
In article <patrick_d_log...@ccm.jf.intel.com>,

Patrick D. Logan <patrick...@ccm.jf.intel.com> wrote:

|In article <2vs6aq$7...@caslon.CS.Arizona.EDU> ne...@CS.Arizona.EDU (Nevin Liber) writes:
|
|>In article <2vnk1g$19...@whale.st.usm.edu>,
|>John William Chambless <cham...@whale.st.usm.edu> wrote:
|
|>>My personal prejudice (isn't that what this discussion REALLY is about?)
|>>is that if a GOTO makes the code clear, and the label is VERY close to
|>>the GOTO (in the same screenful) it's okay.
|
|>That's fine for school projects and one-shot programs. However, as someone
|>who has had to maintain and modify existing code bases, it's impossible to
|>guarantee that the label will remain very close to the GOTO forever.
|
|Now, I'm not arguing for using GOTOs, but this particular argument against
|them does not hold water.

Yes it does. Keep reading.

|If there is a proper use of a GOTO in a piece of code, and if that code is
|*well* maintained, then that use of GOTO should remain "proper" by whatever
|definition the developers have given "proper" to be.
|
|If code is not going to be maintained well, then *all* bets are off.

In the real world, you don't know whether the code will be well maintained
or not. Most likely it will not be, because the average peron-who-gets-paid-
to-write-code is not very good.

|I have
|seen pretty unmaintainable code that does not have any GOTOs and could even
|said to be "structured" (even "object oriented")!

The painfully-obvious fact that bad code can be written without gotos
is irrelevant to the fact that using gotos, with only very, very rare
exceptions (I've never seen it done), makes for less-maintainable code.

Does the fact that fatal accidents are possible in a Volvo prove that a
Yugo is no less safe than a Volvo?

James Allen

unread,
Jul 15, 1994, 4:51:57 AM7/15/94
to
I like to post my own diatribe on `goto's twice a decade or so.
It seems to be that time again....

If I were allowed only a single observation I'd invoke the keyword:
`` **TRADEOFFS** ''
Do you want speed? smallness? readability? If readability is your goal,
does your reader have an open mind or is he so dogmatic and irritable that
his effective IQ slips a few notches whenever his temporal cortex detects
the string `g o t o'?

(I'm not being altogether facetious here. I confess that *I* tend to be too
dogmatic about minor stylistic issues and will be slowed down or turned
off by constructions that don't "suit my taste" even though in more sober
moments I might defend the other programmer's "right" to suit his own taste.)

Let's start with a very simple construction. (If you're in a hurry, `GOTO'
the more interesting example at the end of this post.)

This construction will be very familiar to those of you who read BSD source
for pleasure. I think the version with `goto' is at least as readable:

#ifdef DONT_USE_GOTO
for (i = 0; Predicate_1; i++) {
foo();
if (Predicate_2)
break;
bar();
}
if (! Predicate_1)
giggle();
gargle();
#else
for (i = 0; Predicate_1; i++) {
foo();
if (Predicate_2)
goto happy_label;
bar();
}
giggle();
happy_label:
gargle();
#endif

I like the second fragment --- you `go' where you want to go; you `giggle'
when you want to giggle. As a microprogrammer by training the first
fragment just *looks* wrong: why test `Predicate_1' twice in a row?
(even *if* the compiler is smart enough to elide the redundant test.)

(I realize that without knowing about the side effects of `foo()' and so
on it is impossible to determine if the two fragments above are equivalent.
But this may strengthen my case! Programming the first way may lead to
contortions as you "paraphrase" `Predicate_1' to make it appropriate in
context. With my way you just "go where you want to go.")

Sometimes the first fragment above will work out better, but about 95% of
the time the second fragment will seem more natural to *me*. Which way seems
more natural to you? I don't know, but before rejecting the second fragment
make sure you're not just reacting to an ingrained prejudice against `goto'.

I think most readers will agree that `break' is also sort of "bad" ---
though typically not as "bad" as `goto.' That's my message --- consider
the full gamut of tradeoffs; in the above fragment, for example, the
`break' is particularly bad (because the post-handlings of the `broken' and
completed loops are different) while the `goto' isn't really so vicious here.
I don't feel strongly about the above fragments --- the `DONT_USE_GOTO'
approach seems almost as good as the `goto' way --- but if anyone argues
that the former is significantly better I will suspect pedantry.

Before continuing with specifics, another general observation: different
applications have different priorities. Some of the generalizations that
arise in Usenet discussions border on the silly. Paraphrasing:

> "It's not worth the bother to squeeze out the last 5% of performance."
This is a useful observation most of the time, but arose in a discussion
where someone was spending almost 10^6 dollars for reactor-plant
modeling. The "5% squeeze" alone would have justified his salary
(and these were *taxpayer* dollars :-)

> "Maintainability of the code is far more important than its efficiency"
This may be true of most code but it will seem rather peculiar to a
space-probe engineer who is begging his masters for an extra milliwatt.

In <crdCst...@netcom.com> c...@netcom.com (Craig Dickson) writes:
]In article <KARRELS.94...@elf.mcs.anl.gov>,
]Edward L. Karrels <kar...@mcs.anl.gov> wrote:
]
]|I am normally a non-goto person, but in a recent case I used a few goto's
]
]Did you look at the resulting object code to see if it helped?

???? I suspect a typo here. It's almost certain Edward's straightforward
change had precisely the intended effect on the object code.

Now, whether the added speed was worth the bother is a separate question.
But who are we to question Edward's purpose? If a stranger asks directions
to the top of Mt. Everest I may or may not admire him/her but I *won't* say
"There's not much to do *there*. Let me send you off to
Ghirardelli Square."

Very abbreviated version of Edward's code:
]| for (x) {
]| Stuff();
]| if (DoCheck()) goto lbl1;
]| }
]| return 1;
]| for (x) {
]| Stuff();
]| lbl1:
Don't you want a `; -}' here BTW?
]| }
]| return 0;
]|
]|I think if I tried to do this in a more structured fashion, it would lose
]|the cleanliness of this approach.
]
]You call jumping from the middle of one for loop to the middle of another
]one "clean"? Yow!

Wait till you see the fragment I offer below!! Yipes!!!

]I don't know how much you needed *every* *last* *bit* *of* *speed* in this
]code, but the following is far less noxious and very nearly as fast, ...

I've omitted Craig's version since the tradeoff of speed for space is
obvious here. Like Craig, I'm quite unhappy with Edward's code.
But I don't find it "noxious" and I'm not inclined to care about text size
since Edward implied he didn't. I dislike Edward's version because, simply
put, it uses more keystrokes (or ink) than necessary.

But if speed is sufficiently more important than maintainability it is almost
a tautology that Edward's code is superior. (Craig seems to imply that some
compilers may find Edward's solution themselves, but I don't know any
compilers *that* smart.)

While Edward ends up replicating code for speed, many of the GOTO's I like
are used to *enhance* maintainability by avoiding code replication.
For example:
switch(...) {...
case INSERT:
make_space_for_new_record();
/*FALLTHROUGH*/
case APPEND:
initialize_the_various_fields();
/*FALLTHROUGH*/
case UPDATE:
lots_of_yummy_update_stuff();
...}

Avoiding the `/*FALLTHROUGH*/' (which becomes `goto' in slightly more complex
examples) requires replicating or encapsulating `lots_of_yummy_etc().' `goto'
may not be the *best* approach here, but it's much better than a lot of
alternatives whose *only* merit is that they avoid the 4-letter word `goto.'

I'm obviously in a preaching mood so let me say
"Don't become dogmatic!"
All keystrokes are `bad.' The specific keys `g o t o' are admittedly worse
than most, as a rule, but if you're burning up 100 extra keystrokes just to
placate the `grep goto' police I suggest you retune the weights in your global
cost function.

In <774005...@natron.demon.co.uk> Ro...@natron.demon.co.uk (Roger Barnett) writes:
]Seems to me that the anti-gotos in this thread talk about routines full of
]goto statements jumping all over the place, while the non-anti-gotos talk
]about routines with one or two at most used in some kind of controlled way
]- hey guys, I don't think you're going to reach agreement here !
]
] ... I do find the C "continue" (and "break" in loops to a lesser
]extent) a bit of a pain when trying to maintain code which often contains ...

I'm in full agreement with Roger's sentiments. The idea that `break 2' or
(heaven forbid!) `break 3' is going to be more readable than
`goto get_me_out_of_here' seems absurd to me. It *may* be true (though I'm
not ready to concede it) that a `goto' that is logically equivalent to a
`break N' is somehow much better than an arbitrary `goto' but insisting on
the `break N' syntax not only represents the kind of mind control George
Orwell warned about, but is *more* error-prone, since sometimes a new
`while' loop is added between the levels of an existing nested `while' loop.
(And *don't* write in about your emacs macro that will update the `break N'
statement automatically --- whatever happened to ``Simplicity is a Virtue?'')

In <2vucg4$4...@wcap.centerline.com> ji...@centerline.com (Jim Frost) writes:
]While I agree that multilevel break would be very useful, I'd still


]use a goto in many cases because it would get very difficult to tell
]where the exit point is. A label makes it very obvious.

That's what I was trying to say! Why are you so succinct?

In <300ba1$e...@tuegate.tue.nl> len...@blade.stack.urc.tue.nl (Lennart Benschop) writes:
]In article <2vvlba$s...@nyx10.cs.du.edu>,


]Buddha Buck <bb...@nyx10.cs.du.edu> wrote:
]-In article <1994Jul12.1...@adobe.com>,
]-Ed Taft <ta...@mv.us.adobe.com> wrote:

]->Reminds me of this gem from _C: A Reference Manual_ by Harbison & Steele:
]->


]-> switch (x)
]-> default:
]-> if (prime(x))

]-> case 2: case 3: case 5: case 7:
]-> process_prime(x);
]-
]-/* Somebody tell me why there is no break here? */
]->
]-> else
]-> case 4: case 6: case 8: case 9: case 10:
]-> process_composite(x);
]->
]->They go on to say: "This is, frankly, the most bizarre switch
]->statement we have ever seen that still has pretenses to being
]->purposeful."

This code fragment is of course, very similar to the ``Duff's Device''
--- perhaps the most (in)famous of bizarre C code fragments! I'm sure it's
in many of the FAQL's but I'll e-mail it to anyone who can't find it.

]-It seems to me that it would process 7 as both prime and composite.
]
] if(foo) {bar();} else {baz();}
]is more or less equivalent to
] if(!foo)goto lab1; bar(); goto lab2; lab1: baz(); lab2:

Yes, that's how the C language works. Hmmm, the fact that this wasn't
obvious suggests that the anti-goto fanatics have succeeded in brainwashing
the younger generation! ... If all the compilers disappeared tomorrow
would we be able to bootstrap from machine code again? 1/2 ;-)

And now the moment you've been waiting for. *My* favorite `goto.'
This is real code that solves a real puzzle, and rather promptly at that.
There are several ways to avoid the `goto' but I claim the result would be
less efficient and less *readable*.

I beg forgiveness for posting a code fragment of over 200 lines but note that
this "fragment" is ready to compile and run *as is*. (I tried to formulate
a 50-line pseudo-code synopsis but I'm afraid it would just cause confusion
and e-mail requests. Anyway, by supplying *this* code I give my detractors
plenty of beef to chomp on --- I bet we'll *all* agree that `goto' is the
least of worries with *this* code.)

If you study the code you will conclude that the `goto' will operate properly
only if *all* the local variables are in *precisely* the right state to
take the voyage from Here to There. And that is exactly the concept which
the potential code-maintainer is intended to grasp.

========= bridge.c =========
/*
* DOUBLE_DUMMY
* Copyright (c) 1990 by
* James D. Allen
* 1866 Silvana Lane
* Santa Cruz, CA 95062
*
* This program will solve double-dummy bridge problems.
* The algorithm is trivial: brute-force alpha-beta search (also known
* as "backtracking"). The alpha-beta is especially easy here since
* we do not consider overtricks or extra undertricks.
* The control flow is ``way cool'': this is a rare exception where software
* is more readable with a "goto". (Although I've tersified this to
* the point where it is perhaps unreadable anyway :-)
*
* As is, it should solve 8-card endings in just a few minutes.
* It actually solves *one* complete 52-card position ("13-card ending") much
* faster than humans can, but that special position is sort of a quirk.
*
* This program is "copylefted." You are authorized to use or reproduce it
* as long as you observe all three of the following admonitions:
* (1) Do not sell this software for profit.
* (2) Do not remove the Copyright notice or these admonitions.
* (3) Do not use an alternate construction which avoids the `goto' :-}
*/

#define NUMP 4 /* The Players: N, E, S, W */
#define NORTH 0
#define IS_CONT(x) (!((x) & 1)) /* Is x on N/S team? */
#define LHO(x) (((x) + 1) % NUMP)
#define RHO(x) (((x) + NUMP - 1) % NUMP)
char *Playername[] = { "North", "East", "South", "West" };

#define NUMS 4 /* The Suits: S, H, D, C */
char Suitname[] = "SHDC";
char *Fullname[] = { "Spades ", "Hearts ", "Diamonds", "Clubs ", };

/*
* Rank indices are 2 (Ace), 3 (King), ... 14 (Deuce)
* There is also a CARD Index which can be converted to from Rank and Suit.
*/
#define CARD(Suit, Rank) (((Suit) << 4) | (Rank))
#define SUIT(Card) ((Card) >> 4)
#define RANK(Card) ((Card) & 0xf)
char Rankname[] = "??AKQJT98765432";
#define INDEX(s, c) ((char *)index(s, c) - (s))

/* A "SuitSet" is used to cope with more than one card at once: */
typedef unsigned short SuitSet;
#define MASK(Card) (1 << RANK(Card))
#define REMOVE(Set, Card) ((Set) &= ~(MASK(Card)))

/* And a CardSet copes with one SuitSet for each suit: */
typedef struct cards {
SuitSet cc[NUMS];
} CardSet;

/* Everything we wish to remember about a trick: */
struct status {
CardSet st_hold[NUMP]; /* The players' holdings */
CardSet st_lgl[NUMP]; /* The players' remaining legal plays */
short st_play[NUMP]; /* What the players played */
SuitSet st_trick; /* Led-suit Cards eligible to win trick */
SuitSet st_trump; /* Trump Cards eligible to win trick */
short st_leader; /* Who led to the trick */
short st_suitled; /* Which suit was led */
}
Status[14]; /* Status of 13 tricks and a red zone" */
#define Hold Statp->st_hold
#define Resid (Statp+1)->st_hold
#define Lgl Statp->st_lgl
#define Play Statp->st_play
#define Trick Statp->st_trick
#define Trtrick Statp->st_trump
#define Leader Statp->st_leader
#define Suitled Statp->st_suitled

/* Pick a card from the set and return its index */
pick(set)
SuitSet set;
{
return set & 0xff ? set & 1 ? 0 : set & 2 ? 1 : set & 4 ? 2
: set & 8 ? 3 : set & 16 ? 4 : set & 32 ? 5
: set & 64 ? 6 : 7 : pick(set >> 8) + 8;
}

#define highcard(set) pick(set) /* Pick happens to return the best card */

main()
{
register struct status *Statp = Status; /* Point to current status */
int tnum; /* trick number */
int won; /* Total tricks won by North/South */
int nc; /* cards on trick */
int ohsize; /* original size of hands */
int mask;
int trump;
int player; /* player */
int pwin; /* player who won trick */
int suit; /* suit to play */
int wincard; /* card which won the trick */
int need; /* Total tricks needed by North/South */
int cardx; /* Index of a card under consideration */
int success; /* Was the trick or contract won by North/South ? */
int last_t; /* Decisive trick number */
char asciicard[60];
SuitSet inplay; /* cards still in play for suit */
SuitSet pr_set; /* Temp for printing */

/* Read in the problem */
printf("Enter trump suit (0-S,1-H,2-D,3-C,4-NT): ");
scanf("%d", &trump);
printf("Enter how many tricks remain to be played: ");
scanf("%d", &ohsize);
printf("Enter how many tricks North/South need to win: ");
scanf("%d", &need);
printf("Enter who is on lead now (0=North,etc.): ");
scanf("%d", &pwin);
printf("Enter the %d cards beginning with North:\n", NUMP * ohsize);
for (player = NORTH; player < NUMP; player++) {
for (tnum = 0; tnum < ohsize; tnum++) {
scanf("%s", asciicard);
cardx = CARD(INDEX(Suitname, asciicard[1]),
INDEX(Rankname, asciicard[0]));
Hold[player].cc[SUIT(cardx)] |= MASK(cardx);
}
}

/* Handle the opening lead */
printf("Enter the directed opening lead or XX if none:\n");
Lgl[pwin] = Hold[pwin];
scanf("%s", asciicard);
if (asciicard[0] == 'X') {
strcpy(asciicard, "anything");
} else {
cardx = CARD(INDEX(Suitname, asciicard[1]),
INDEX(Rankname, asciicard[0]));
for (suit = 0; suit < NUMS; suit++)
if (suit != SUIT(cardx))
Lgl[pwin].cc[suit] = 0;
else if (!(Lgl[pwin].cc[suit] &= MASK(cardx))) {
printf("He can't lead card he doesn't have\n");
exit(1);
}
}

/* Print the problem */
for (player = NORTH; player < NUMP; player++) {
printf("\n---- %s Hand ----:\n", Playername[player]);
for (suit = 0; suit < NUMS; suit++) {
printf("\t%s\t", Fullname[suit]);
for (pr_set = Hold[player].cc[suit]; pr_set;
REMOVE(pr_set, pick(pr_set)))
printf("%c ", Rankname[RANK(pick(pr_set))]);
printf("\n");
}
}
printf("\n%s%s Trumps; %s leads %s; N-S want %d tricks; E-W want %d\n",
trump < NUMS ? Fullname[trump] : "",
trump < NUMS ? " are" : "No",
Playername[pwin], asciicard, need, ohsize + 1 - need);

/* Loop to play tricks forward until the outcome is conclusive */
for (tnum = won = success = 0;
success ? ++won < need : won + ohsize >= need + tnum;
tnum++, Statp++, success = IS_CONT(pwin)) {
for (nc = 0, player = Leader = pwin; nc < NUMP;
nc++, player = LHO(player)) {
/* Generate legal plays except opening lead */
if (nc || tnum)
Lgl[player] = Hold[player];
/* Must follow suit unless void */
if (nc && Lgl[player].cc[Suitled])
for (suit = 0; suit < NUMS; suit++)
if (suit != Suitled)
Lgl[player].cc[suit] = 0;
goto choose_suit; /* this goto is easily eliminated */
/* Comes back right away after choosing "suit" */
make_play:
Play[player] = cardx =
CARD(suit, pick(Lgl[player].cc[suit]));
if (nc == 0) {
Suitled = suit;
Trick = Trtrick = 0;
}
/* Set the play into "Trick" if it is win-eligible */
if (suit == Suitled)
Trick |= MASK(cardx);
if (suit == trump)
Trtrick |= MASK(cardx);

/* Remove card played from player's holding */
Resid[player] = Hold[player];
REMOVE(Resid[player].cc[suit], cardx);
}

/* Finish processing the trick ... who won? */
if (Trtrick)
wincard = CARD(trump, highcard(Trtrick));
else
wincard = CARD(Suitled, highcard(Trick));
for (pwin = 0; Play[pwin] != wincard; pwin++)
;
}

/* Loop to back up and let the players try alternatives */
for (last_t = tnum--, Statp--; tnum >= 0; tnum--, Statp--) {
won -= IS_CONT(pwin);
pwin = Leader;
for (player = RHO(Leader), nc = NUMP-1; nc >= 0;
player = RHO(player), nc--) {
/* What was the play? */
cardx = Play[player];
suit = SUIT(cardx);
/* Retract the played card */
if (suit == Suitled)
REMOVE(Trick, cardx);
if (suit == trump)
REMOVE(Trtrick, cardx);
/* We also want to remove any redundant adjacent plays */
inplay = Hold[0].cc[suit] | Hold[1].cc[suit]
| Hold[2].cc[suit] | Hold[3].cc[suit];
for (mask = MASK(cardx); mask <= 0x8000; mask <<= 1)
if (Lgl[player].cc[suit] & mask)
Lgl[player].cc[suit] &= ~mask;
else if (inplay & mask)
break;
/* If the card was played by a loser, try again */
if (success ? !(IS_CONT(player)) : IS_CONT(player)) {
choose_suit:
/* Pick a suit if any untried plays remain */
for (suit = 0; suit < NUMS; suit++)
if (Lgl[player].cc[suit])
/* This goto is really nice!! */
goto make_play;
}
}
}

/*
* We're done. We know the answer.
* We can't remember all the variations; fortunately the
* succeeders played correctly in the last variation examined,
* so we'll just print it.
*/
printf("Contract %s, for example:\n",
success ? "made" : "defeated");
for (tnum = 0, Statp = Status; tnum < last_t; tnum++, Statp++) {
printf("Trick %d:", tnum + 1);
for (player = 0; player < Leader; player++)
printf("\t");
for (nc = 0; nc < NUMP; nc++, player = LHO(player))
printf("\t%c of %c",
Rankname[RANK(Play[player])],
Suitname[SUIT(Play[player])]);
printf("\n");
}
return 0;
}
============ Test examples =========
bridge << EOF
4 6 5 2
AS JS 4S QD 8D 2C
KS QS 9H 8H AD 2D
AH 2H KD 9D 7D AC
TS 3S 2S TH TD TC
XX
EOF
bridge << EOF
1 13 13 3
3C 3H 2H AD KD 2D AS KS 7S 6S 5S 4S 3S
8C 7C 6C 5C 4C QH TH 8H 7H 8D 7D 6D 2S
AC QC JC 9C AH KH JH 9H 6H 5H 5D 4D 3D
KC TC 2C 4H QD JD TD 9D QS JS TS 9S 8S
QS
EOF
==================

Raul Deluth Miller

unread,
Jul 15, 1994, 11:03:54 AM7/15/94
to
Hmm... looking at the bridge code, I notice one thing right off: this
code isn't factored at all. There's just one routine, main().

So, right off, this code isn't a very good example of maintainability.

Second, the particular example of a goto this code presents could
easily be handled by a return from a subfunction [where there's a loop
in the subfunction].

Raul D. Miller n =: p*q NB. prime p, q, e
<rock...@nova.umd.edu> NB. public e, n, y
y =: n&|&(*&x)^:e 1
x -: n&|&(*&y)^:d 1 NB. 1 < (d*e) +.&<: (p,q)

William Chesters

unread,
Jul 15, 1994, 10:17:57 AM7/15/94
to
In article <1994Jul15.0...@crc.ricoh.com>, ja...@crc.ricoh.com (James Allen) writes:

# #ifdef DONT_USE_GOTO
# for (i = 0; Predicate_1; i++) {
# foo();
# if (Predicate_2)
# break;
# bar();
# }
# if (! Predicate_1)
# giggle();
# gargle();
# #else
# for (i = 0; Predicate_1; i++) {
# foo();
# if (Predicate_2)
# goto happy_label;
# bar();
# }
# giggle();
# happy_label:
# gargle();
# #endif

The `goto' version is also a lot clearer than this:

for (i = 0;; i++) {
if (..p1..) {
foo();
if (..p2..) break;
bar();
} else {
giggle();
break;
}
}
gargle();

I suppose because the loop doesn't really look like a loop.

--
William Chesters (will...@aifh.ed.ac.uk)
Computer vision? I'll believe that when it sees me.

Raul Deluth Miller

unread,
Jul 15, 1994, 11:38:45 AM7/15/94
to
James Allen:
. #ifdef DONT_USE_GOTO
. for (i = 0; Predicate_1; i++) {
. foo();
. if (Predicate_2)
. break;
. bar();
. }
. if (! Predicate_1)
. giggle();
. gargle();
. #else
. for (i = 0; Predicate_1; i++) {
. foo();
. if (Predicate_2)
. goto happy_label;
. bar();
. }
. giggle();
. happy_label:
. gargle();
. #endif

Notes:

[a] these are not necessarily equivalent [unless Predicate_1 is free
of side effects].

[b] for the cases where they are equivalent, a good optimizing
compiler should produce the same code for them.

[c] another way of writing this [for the case where Predicate_1 is
free of side effects] might be:

belch();
gargle();

where the following are defined:

belch() {
if (Predicate_1()) {
snort();
} else {
giggle();
}
}

snort() {
int i= 0;
do {
foo();
if (Predicate_2()) {
return;
}
bar();
i++;
} while (Predicate_1());
}

compile this with -finline-functions [or the equivalent], and you're
just as efficient as the unmodularized original.

Craig Dickson

unread,
Jul 15, 1994, 11:46:22 AM7/15/94
to
In article <1994Jul15.0...@crc.ricoh.com>,
James Allen <ja...@crc.ricoh.com> wrote:

I find both versions slightly brain-damaged. Why not simply:

for (i = 0; Predicate_1; i++) {
foo();

if (Predicate_2) {
giggle();
break;
}
bar();
}
gargle();

The following discussion assumes, as does James' "goto" version, that
foo() does not affect the result of Predicate_1. If foo() does affect
Predicate_1, then the original code is perfectly reasonable; the extra
test is necessary. But otherwise:

Looking at James' examples, clearly !Predicate_1 will only be TRUE if
the for loop completed normally, without Predicate_2 ever triggering
the break; which means that we only want to giggle() if Predicate_2 is
TRUE, so why not put giggle() in its logical place inside the 'if
(Predicate_2)' statement?

So far several people have given us small code samples intended to
demonstrate a situation in which a goto is desirable. I believe I have
countered every one of them by giving an alternate version which is
more readable and, in all but one case (Edward's rather ugly duplicate-
loops) at least as fast. (Even in that case, unless every possible cycle
needs to be saved -- not usually the case -- my version is not slower in
any significant way.) I think this clearly proves my point that *most*
gotos are unnecessary and indicative of poor programming habits or
simple mental laziness. I won't say that *all* gotos are bad; just every
goto I've ever seen.

|I think most readers will agree that `break' is also sort of "bad" ---
|though typically not as "bad" as `goto.'

No, I have no problems at all with 'break', 'continue', or explicit use
of 'return' in the middle of a function. These, like anything else, can
be abused, but it seems to me that they are far more often used correctly
than goto. The simple fact is that not all loops can be reasonably coded
with all the exit tests in one place; sometimes you need to test X at the
top of the loop and Y somewhere in the middle, and forcing this into a
'while (X && Y)' construction may only serve to unnecessarily complicate
the code. In such cases, it seems much more reasonable to me to implement
the loop as 'while (X)', with an 'if (Y) break;' in the appropriate place.
YMMV.

Ultimately it comes down (for me) to the fact that break and continue work
within the structure of the code, having meaning only in the context of a
given loop or switch statement, and always behaving in a very simple
manner (exit this loop, or immediately start the next iteration of it).
They cannot act in an arbitrary and structure-violating way as goto can
and, in practice, usually does.

|In <crdCst...@netcom.com> c...@netcom.com (Craig Dickson) writes:
|]In article <KARRELS.94...@elf.mcs.anl.gov>,
|]Edward L. Karrels <kar...@mcs.anl.gov> wrote:
|]
|]|I am normally a non-goto person, but in a recent case I used a few goto's
|]
|]Did you look at the resulting object code to see if it helped?
|
|???? I suspect a typo here. It's almost certain Edward's straightforward
|change had precisely the intended effect on the object code.

Almost certain is not certain. What if, for instance, your compiler's
reaction to seeing a 'goto' is to shut off certain optimizations in
that function?

|The idea that `break 2' or
|(heaven forbid!) `break 3' is going to be more readable than
|`goto get_me_out_of_here' seems absurd to me. It *may* be true (though I'm
|not ready to concede it) that a `goto' that is logically equivalent to a
|`break N' is somehow much better than an arbitrary `goto' but insisting on
|the `break N' syntax not only represents the kind of mind control George
|Orwell warned about, but is *more* error-prone, since sometimes a new
|`while' loop is added between the levels of an existing nested `while' loop.

Absolutely! 'Break N' is one of those notions that sounds neat at first,
but has some very serious dangers when you look at it in detail. What
would be much better would be named loops, such as in the following:

while (predicate) "MyLoop" {
for (foo; bar; baz) {
quux();
if (predicate2)
break "MyLoop";
qaax();
}
blah();
}

Note that this syntax does two useful things: (1) the break is tied to a
name, so the insertion or deletion of intermediate loops will not affect
it; (2) the name doesn't look like a label that could be used for a goto.
I like this latter property because when I see a label in a function
(other than in a switch) I wonder how many gotos reference it. Rather
annoying.

|In <2vucg4$4...@wcap.centerline.com> ji...@centerline.com (Jim Frost) writes:
|]While I agree that multilevel break would be very useful, I'd still
|]use a goto in many cases because it would get very difficult to tell
|]where the exit point is. A label makes it very obvious.

The "named loop" concept is just as good as a label, I think, but because
syntactically it isn't one, you don't have to check for other gotos that
might be referencing it.

|]-It seems to me that it would process 7 as both prime and composite.
|]
|] if(foo) {bar();} else {baz();}
|]is more or less equivalent to
|] if(!foo)goto lab1; bar(); goto lab2; lab1: baz(); lab2:
|
|Yes, that's how the C language works. Hmmm, the fact that this wasn't
|obvious suggests that the anti-goto fanatics have succeeded in brainwashing
|the younger generation!

No, it suggests that the person who misread the code doesn't understand
C very well. It *is* perfectly obvious.

| ... If all the compilers disappeared tomorrow
|would we be able to bootstrap from machine code again? 1/2 ;-)

It would probably have a wonderful effect on the industry, because people
who don't know assembly language (and therefore don't really understand
*any* language) would suddenly be out of a job. 1/2 :-)

I do hope that no one is mistaking me for Nicklaus Wirth in this debate.
I am not an academic, but a working engineer, and I'm in favor of coding
practices that I have found to produce the best, most maintainable code.
Obviously *any* rule will have its exceptions; but if the rules are well
chosen, those exceptions will be quite rare. In my experience, "don't
use gotos" is a good rule. I agree that there may be, somewhere, a case
in which a goto was used properly. I have not, however, seen it.

|And now the moment you've been waiting for. *My* favorite `goto.'
|This is real code that solves a real puzzle, and rather promptly at that.
|There are several ways to avoid the `goto' but I claim the result would be
|less efficient and less *readable*.

You call a two-hundred-line function readable? Puh-leeze.

|I beg forgiveness for posting a code fragment of over 200 lines but note that
|this "fragment" is ready to compile and run *as is*. (I tried to formulate
|a 50-line pseudo-code synopsis but I'm afraid it would just cause confusion
|and e-mail requests. Anyway, by supplying *this* code I give my detractors
|plenty of beef to chomp on --- I bet we'll *all* agree that `goto' is the
|least of worries with *this* code.)

True. The fact that the entire program is in main() is the real problem
with this code. That's why you needed the goto in the first place.

Gerald Reno

unread,
Jul 15, 1994, 3:50:02 PM7/15/94
to
In article <2vrb29$h...@owl.csrv.uidaho.edu>,
Mark Hughes <hugh...@buzzard.csrv.uidaho.edu> wrote:
>On 11 Jul 1994 09:05:49 GMT, Markus Freericks (m...@cs.tu-berlin.de) is alleged to have written:
>: One point that I have not yet seen considered in this discussion is the
>: following one: there are two well-known languages that depend heavily on
>: GOTO-mediated control flow. These are FORTRAN and BASIC. Both languages did
>: only provide _numeric labels_ (i.e., line numbers) as destinations for GOTO
>: statements (at least in their early definitions). How much of the
>: spaghetti-ness of Fortran-66 and BASIC programs is due to the confusion
>: caused by this restriction to non-symbolic labels?
>
> Well, back when I programmed in Atari Basic (and I wrote structured programs
>with only stone knives and bear..., er, with only goto, if, and for), I
>discovered that variable references were faster than constants, so I used the
>calculated goto and named all important line numbers with variables at the start
>of the program:
>

In the interest of bringing some history into the discussion...

This was a pretty well known fact, and I once found a
preprocessor which allowed you to write your code in Your
Favorite Text Editor, using only symbolic labels, and no line
numbers whatsoever.

It worked very well; the nuisance was repeatedly rebooting to
switch cartridges from AtariWriter and BASIC, running the
preprocessor, loading in the new code (actually using 'ENTER')
and then running it.

No, I don't remember the name; it came from either ANTIC or
ANALOG magazine, round about '87.

Jerry Reno (Yes, I said CARTRIDGE. Bring back the Cartridge!)
glr...@afterlife.ncsc.mil
GCS d-- -p+ c++ l u+ e++(*) m+ s n@ h--- f?(*) g-(+++) w+ t++ r y?

Brett Middleton

unread,
Jul 15, 1994, 4:14:18 PM7/15/94
to
ja...@crc.ricoh.com (James Allen) writes:

>I like to post my own diatribe on `goto's twice a decade or so.
>It seems to be that time again....
[munch]

>> "It's not worth the bother to squeeze out the last 5% of performance."
>This is a useful observation most of the time, but arose in a discussion
>where someone was spending almost 10^6 dollars for reactor-plant
>modeling. The "5% squeeze" alone would have justified his salary
>(and these were *taxpayer* dollars :-)

I'll let everyone else fight the goto battle with you, but I didn't
want to let the above pass without comment.

As the statement is phrased it appears that the 10^6 represents the
development cost, not the run cost. Therefore, squeezing out that
last 5% will probably _increase_ that $ figure by some amount, not
reduce it by 5%. Further, getting that final 5% is usually done
by making the code far less maintainable and probably less robust.
(I.e., the programmer starts turning out chunks of self-modifying
code and such to reach that peak.) Thus the maintenance costs for
the life of the system will increase, and there will be additional
cost in lost productivity every time that thoroughly-joe'd code
goes down.

So, the question becomes: will a 5% reduction in run costs pay
back the development effort required to achieve it, plus the costs
of downtime while the thing is being fixed? I've rarely seen a
case where the answer to that is "yes."

If the 10^6 really is run cost, then the answer may be "yes." But
if that's the run cost, the development cost must be _astounding_,
leading me to suspect that the answer is still "no."

Brett

*SLMW 1.0* Closet PL/I programmer. Native VSE bigot. CAI booster.

Greg Limes

unread,
Jul 16, 1994, 1:16:04 AM7/16/94
to
In article <2vud6j$5...@wcap.centerline.com>,
Jim Frost <ji...@centerline.com> wrote:
>I wouldn't have ever written something like that, and would have sworn
>it was illegal, but I ran into "production" code with similar
>constructs written by a man whom I believe to be insane. He basically
>wrote:
>
> switch (foo) {
> case 1:
> if (bar) {
> case 2:
> /* ... */
> }
> }

You think that is insane? Check this out ...

void
WriteWordToPort(data, port, count)
unsigned *data;
volatile unsigned *port;
unsigned count;
{
register m = count & 7;
register n = count >> 3;

data += m;

switch (m)
do {
*port = data[0];
data += 8;
case 7: *port = data[-7];
case 6: *port = data[-6];
case 5: *port = data[-5];
case 4: *port = data[-4];
case 3: *port = data[-3];
case 2: *port = data[-2];
case 1: *port = data[-1];
case 0: ;
} while (--n >= 0);
}


(hands up, all those who recognize Duff's Device, even
mutated this badly ... the above is optimal for some
particular CPUs)
--
Greg Limes [not speaking for 3DO]
#include <disclaimer.h>
When cryptography is outlawed, bayl bhgynjf jvyy unir cevinpl.
PGP 0x1873DB65 // 12 8B 30 43 AA 88 8E F7 DD 50 97 D2 84 FD 5A 5C

Thomas Lawrence

unread,
Jul 16, 1994, 9:05:09 PM7/16/94
to
In article <crdCsz...@netcom.com> c...@netcom.com (Craig Dickson) writes:
>So far several people have given us small code samples intended to
>demonstrate a situation in which a goto is desirable. I believe I have
>countered every one of them by giving an alternate version which is
>more readable and, in all but one case (Edward's rather ugly duplicate-
>loops) at least as fast. (Even in that case, unless every possible cycle
>needs to be saved -- not usually the case -- my version is not slower in
>any significant way.) I think this clearly proves my point that *most*
>gotos are unnecessary and indicative of poor programming habits or
>simple mental laziness. I won't say that *all* gotos are bad; just every
>goto I've ever seen.

The following code must avoid leaking memory.

Can you suggest how to remove the gotos from this function (short of using
a language with proper exception handling)?

Can you suggest how to 'factor' it into sub-functions meaningfully?

----------------------------------------------------------------------------
TrackWindowRec* NewTrackWindow(struct TrackObjectRec* TrackObject,
struct MainWindowRec* MainWindow,
struct TrackListRec* TrackList, short WinX, short WinY,
short WinWidth, short WinHeight)
{
TrackWindowRec* Window;
OrdType ButtonX;

/* deal with window placement */
if ((WinWidth < 100) || (WinHeight < 100) || ((eOptionKey & CheckModifiers()) != 0))
{
WinX = 1 + WindowOtherEdgeWidths(eDocumentWindow);
WinY = 1 + WindowTitleBarHeight(eDocumentWindow);
WinWidth = WINDOWXSIZE;
WinHeight = WINDOWYSIZE;
}
MakeWindowFitOnScreen(&WinX,&WinY,&WinWidth,&WinHeight);

Window = (TrackWindowRec*)AllocPtrCanFail(sizeof(TrackWindowRec),"TrackWindowRec");
if (Window == NIL)
{
FailurePoint1:
return NIL;
}
Window->MainWindow = MainWindow;
Window->TrackObject = TrackObject;
Window->TrackList = TrackList;

Window->ScreenID = MakeNewWindow(eDocumentWindow,eWindowClosable,eWindowZoomable,
eWindowResizable,WinX,WinY,WinWidth,WinHeight,(void (*)(void*))&TrackWindowUpdator,
Window);
if (Window->ScreenID == 0)
{
FailurePoint2:
ReleasePtr((char*)Window);
goto FailurePoint1;
}

Window->HScroll = NewScrollBar(Window->ScreenID,eHScrollBar,HSCROLLX,
HSCROLLY(WinHeight),HSCROLLWIDTH(WinWidth));
if (Window->HScroll == NIL)
{
FailurePoint3:
KillWindow(Window->ScreenID);
goto FailurePoint2;
}

Window->VScroll = NewScrollBar(Window->ScreenID,eVScrollBar,VSCROLLX(WinWidth),
VSCROLLY,VSCROLLHEIGHT(WinHeight));
if (Window->VScroll == NIL)
{
FailurePoint4:
DisposeScrollBar(Window->HScroll);
goto FailurePoint3;
}

ButtonX = BUTTONSXSTART;

Window->ArrowButton = NewIconButtonPreparedBitmaps(Window->ScreenID,ButtonX,BUTTONSY,
BUTTONWIDTH,BUTTONHEIGHT,ArrowButtonBits,ArrowButtonMouseDownBits,
ArrowButtonSelectedBits,ArrowButtonSelectedMouseDownBits,eIconRadioMode);
if (Window->ArrowButton == NIL)
{
FailurePoint5:
DisposeScrollBar(Window->VScroll);
goto FailurePoint4;
}
ButtonX += BUTTONINCREMENT + BUTTONEXOINCREMENT;

Window->CommandButton = NewIconButtonPreparedBitmaps(Window->ScreenID,ButtonX,
BUTTONSY,BUTTONWIDTH,BUTTONHEIGHT,CommandButtonBits,CommandButtonMouseDownBits,
CommandButtonSelectedBits,CommandButtonSelectedMouseDownBits,eIconRadioMode);
if (Window->CommandButton == NIL)
{
FailurePoint5point1:
DisposeIconButton(Window->ArrowButton);
goto FailurePoint5;
}
ButtonX += BUTTONINCREMENT + BUTTONEXOINCREMENT;

Window->SixtyFourthButton = NewIconButtonPreparedBitmaps(Window->ScreenID,
ButtonX,BUTTONSY,BUTTONWIDTH,BUTTONHEIGHT,SixtyFourthButtonBits,
SixtyFourthButtonMouseDownBits,SixtyFourthButtonSelectedBits,
SixtyFourthButtonSelectedMouseDownBits,eIconRadioMode);
if (Window->SixtyFourthButton == NIL)
{
FailurePoint6:
DisposeIconButton(Window->CommandButton);
goto FailurePoint5point1;
}
ButtonX += BUTTONINCREMENT;

Window->ThirtySecondButton = NewIconButtonPreparedBitmaps(Window->ScreenID,
ButtonX,BUTTONSY,BUTTONWIDTH,BUTTONHEIGHT,ThirtySecondButtonBits,
ThirtySecondButtonMouseDownBits,ThirtySecondButtonSelectedBits,
ThirtySecondButtonSelectedMouseDownBits,eIconRadioMode);
if (Window->ThirtySecondButton == NIL)
{
FailurePoint7:
DisposeIconButton(Window->SixtyFourthButton);
goto FailurePoint6;
}
ButtonX += BUTTONINCREMENT;

Window->SixteenthButton = NewIconButtonPreparedBitmaps(Window->ScreenID,
ButtonX,BUTTONSY,BUTTONWIDTH,BUTTONHEIGHT,SixteenthButtonBits,
SixteenthButtonMouseDownBits,SixteenthButtonSelectedBits,
SixteenthButtonSelectedMouseDownBits,eIconRadioMode);
if (Window->SixteenthButton == NIL)
{
FailurePoint8:
DisposeIconButton(Window->ThirtySecondButton);
goto FailurePoint7;
}
ButtonX += BUTTONINCREMENT;

Window->EighthButton = NewIconButtonPreparedBitmaps(Window->ScreenID,
ButtonX,BUTTONSY,BUTTONWIDTH,BUTTONHEIGHT,EighthButtonBits,
EighthButtonMouseDownBits,EighthButtonSelectedBits,
EighthButtonSelectedMouseDownBits,eIconRadioMode);
if (Window->EighthButton == NIL)
{
FailurePoint9:
DisposeIconButton(Window->SixteenthButton);
goto FailurePoint8;
}
ButtonX += BUTTONINCREMENT;

Window->QuarterButton = NewIconButtonPreparedBitmaps(Window->ScreenID,
ButtonX,BUTTONSY,BUTTONWIDTH,BUTTONHEIGHT,QuaterButtonBits,
QuarterButtonMouseDownBits,QuarterButtonSelectedBits,
QuarterButtonSelectedMouseDownBits,eIconRadioMode);
if (Window->QuarterButton == NIL)
{
FailurePoint10:
DisposeIconButtn(Window->EighthButton);
goto FailurePoint9;
}
ButtonX += BUTTONINCREMENT;

Window->HalfButton = NewIconButtonPreparedBitmaps(Window->ScreenID,
ButtonX,BUTTONSY,BUTTONWIDTH,BUTTONHEIGHT,HalfButtonBits,HalfButtonMouseDownBits,
HalfButtonSelectedBits,HalfButtonSelectedMouseDownBits,eIconRadioMode);
if (Window->HalfButton == NIL)
{
FailurePoint11:
DisposeIconButton(Window->QuarterButton);
goto FailurePoint10;
}
ButtonX += BUTTONINCREMENT;

Window->WholeButton = NewIconButtonPreparedBitmaps(Window->ScreenID,
ButtonX,BUTTONSY,BUTTONWIDTH,BUTTONHEIGHT,WholeButtonBits,WholeButtonMouseDownBits,
WholeButtonSelectedBits,WholeButtonSelectedMouseDownBits,eIconRadioMode);
if (Window->WholeButton == NIL)
{
FailurePoint12:
DisposeIconButton(Window->HalfButton);
goto FailurePoint11;
}
ButtonX += BUTTONINCREMENT;

Window->DoubleButton = NewIconButtonPreparedBitmaps(Window->ScreenID,ButtonX,
BUTTONSY,BUTTONWIDTH,BUTTONHEIGHT,DoubleButtonBits,DoubleButtonMouseDownBits,
DoubleButtonSelectedBits,DoubleButtonSelectedMouseDownBits,eIconRadioMode);
if (Window->DoubleButton == NIL)
{
FailurePoint13:
DisposeIconButton(Window->WholeButton);
goto FailurePoint12;
}
ButtonX += BUTTONINCREMENT;

Window->QuadButton = NewIconButtonPreparedBitmaps(Window->ScreenID,ButtonX,
BUTTONSY,BUTTONWIDTH,BUTTONHEIGHT,QuadButtonBits,QuadButtonMouseDownBits,
QuadButtonSelectedBits,QuadButtonSelectedMouseDownBits,eIconRadioMode);
if (Window->QuadButton == NIL)
{
FailurePoint14:
DisposeIconButton(Window->DoubleButton);
goto FailurePoint13;
}
ButtonX += BUTTONINCREMENT + BUTTONEXOINCREMENT;

Window->SharpButton = NewIconButtonPreparedBitmaps(Window->ScreenID,ButtonX,
BUTTONSY,BUTTONWIDTH,BUTTONHEIGHT,SharpButtonBits,SharpButtonMouseDownBits,
SharpButtonSelectedBits,SharpButtonSelectedMouseDownBits,eIconRadioMode);
if (Window->SharpButton == NIL)
{
FailurePoint15:
DisposeIconButton(Window->QuadButton);
goto FailurePoint14;
}
ButtonX += BUTTONINCREMENT;

Window->FlatButton = NewIconButtonPreparedBitmaps(Window->ScreenID,ButtonX,
BUTTONSY,BUTTONWIDTH,BUTTONHEIGHT,FlatButtonBits,FlatButtonMouseDownBits,
FlatButtonSelectedBits,FlatButtonSelectedMouseDownBits,eIconRadioMode);
if (Window->FlatButton == NIL)
{
FailurePoint16:
DisposeIconButton(Window->SharpButton);
goto FailurePoint15;
}
ButtonX += BUTTONINCREMENT;

Window->NaturalButton = NewIconButtonPreparedBitmaps(Window->ScreenID,ButtonX,
BUTTONSY,BUTTONWIDTH,BUTTONHEIGHT,NaturalButtonBits,NaturalButtonMouseDownBits,
NaturalButtonSelectedBits,NaturalButtonSelectedMouseDownBits,eIconRadioMode);
if (Window->NaturalButton == NIL)
{
FailurePoint17:
DisposeIconButton(Window->FlatButton);
goto FailurePoint16;
}
ButtonX += BUTTONINCREMENT + BUTTONEXOINCREMENT;

Window->NoteVsRestButton = NewIconButtonPreparedBitmaps(Window->ScreenID,
ButtonX,BUTTONSY,BUTTONWIDTH,BUTTONHEIGHT,NoteVsRestButtonBits,
NoteVsRestButtonMouseDownBits,NoteVsRestButtonSelectedBits,
NoteVsRestButtonSelectedMouseDownBits,eIconRadioMode);
if (Window->NoteVsRestButton == NIL)
{
FailurePoint18:
DisposeIconButton(Window->NaturalButton);
goto FailurePoint17;
}
ButtonX += BUTTONINCREMENT;

Window->RestVsNoteButton = NewIconButtonPreparedBitmaps(Window->ScreenID,
ButtonX,BUTTONSY,BUTTONWIDTH,BUTTONHEIGHT,RestVsNoteButtonBits,
RestVsNoteButtonMouseDownBits,RestVsNoteButtonSelectedBits,
RestVsNoteButtonSelectedMouseDownBits,eIconRadioMode);
if (Window->RestVsNoteButton == NIL)
{
FailurePoint19:
DisposeIconButton(Window->NoteVsRestButton);
goto FailurePoint18;
}
ButtonX += BUTTONINCREMENT + BUTTONEXOINCREMENT;

Window->NoDotButton = NewIconButtonPreparedBitmaps(Window->ScreenID,ButtonX,
BUTTONSY,BUTTONWIDTH,BUTTONHEIGHT,NoDotButtonBits,NoDotButtonMouseDownBits,
NoDotButtonSelectedBits,NoDotButtonSelectedMouseDownBits,eIconRadioMode);
if (Window->NoDotButton == NIL)
{
FailurePoint20:
DisposeIconButton(Window->RestVsNoteButton);
goto FailurePoint19;
}
ButtonX += BUTTONINCREMENT;

Window->YesDotButton = NewIconButtonPreparedBitmaps(Window->ScreenID,ButtonX,
BUTTONSY,BUTTONWIDTH,BUTTONHEIGHT,YesDotButtonBits,YesDotButtonMouseDownBits,
YesDotButtonSelectedBits,YesDotButtonSelectedMouseDownBits,eIconRadioMode);
if (Window->YesDotButton == NIL)
{
FailurePoint21:
DisposeIconButton(Window->NoDotButton);
goto FailurePoint20;
}
ButtonX += BUTTONINCREMENT + BUTTONEXOINCREMENT;

Window->Div1Button = NewIconButtonPreparedBitmaps(Window->ScreenID,ButtonX,
BUTTONSY,BUTTONWIDTH,BUTTONHEIGHT,Div1ButtonBits,Div1ButtonMouseDownBits,
Div1ButtonSelectedBits,Div1ButtonSelectedMouseDownBits,eIconRadioMode);
if (Window->Div1Button == NIL)
{
FailurePoint22:
DisposeIconButton(Window->YesDotButton);
goto FailurePoint21;
}
ButtonX += BUTTONINCREMENT;

Window->Div3Button = NewIconButtonPreparedBitmaps(Window->ScreenID,ButtonX,
BUTTONSY,BUTTONWIDTH,BUTTONHEIGHT,Div3ButtonBits,Div3ButtonMouseDownBits,
Div3ButtonSelectedBits,Div3ButtonSelectedMouseDownBits,eIconRadioMode);
if (Window->Div3Button == NIL)
{
FailurePoint23:
DisposeIconButton(Window->Div1Button);
goto FailurePoint22;
}
ButtonX += BUTTONINCREMENT;

Window->Div5Button = NewIconButtonPreparedBitmaps(Window->ScreenID,ButtonX,
BUTTONSY,BUTTONWIDTH,BUTTONHEIGHT,Div5ButtonBits,Div5ButtonMouseDownBits,
Div5ButtonSelectedBits,Div5ButtonSelectedMouseDownBits,eIconRadioMode);
if (Window->Div5Button == NIL)
{
FailurePoint24:
DisposeIconButton(Window->Div3Button);
goto FailurePoint23;
}
ButtonX += BUTTONINCREMENT;

Window->Div7Button = NewIconButtonPreparedBitmaps(Window->ScreenID,ButtonX,
BUTTONSY,BUTTONWIDTH,BUTTONHEIGHT,Div7ButtonBits, Div7ButtonMouseDownBits,
Div7ButtonSelectedBits,Div7ButtonSelectedMouseDownBits,eIconRadioMode);
if (Window->Div7Button == NIL)
{
FailurePoint25:
DisposeIconButton(Window->Div5Button);
goto FailurePoint24;
}

Window->TrackView = NewTrackView(TrackObject,Window->ScreenID,TRACKVIEWX,
TRACKVIEWY,TRACKVIEWWIDTH(WinWidth),TRACKVIEWHEIGHT(WinHeight));
if (Window->TrackView == NIL)
{
FailurePoint26:
DisposeIconButton(Window->Div7Button);
goto FailurePoint25;
}

Window->MyGenericWindow = CheckInNewWindow(Window->ScreenID,Window,
(void (*)(void*,MyBoolean,OrdType,OrdType,ModifierFlags))&TrackWindowDoIdle,
(void (*)(void*))&TrackWindowBecomeActive,
(void (*)(void*))&TrackWindowBecomeInactive,
(void (*)(void*))&TrackWindowJustResized,
(void (*)(OrdType,OrdType,ModifierFlags,void*))&TrackWindowDoMouseDown,
(void (*)(unsigned char,ModifierFlags,void*))&TrackWindowDoKeyDown,
(void (*)(void*))&TrackWindowClose,
(void (*)(void*))&TrackWinowMenuSetup,
(void (*)(void*,MenuItemType*))&TrackWindowDoMenuCommand);
if (Window->MyGenericWindow == NIL)
{
FailurePoint27:
DisposTrackView(Window->TrackView);
goto FailurePoint26;
}

Window->MyMenuItem = MakeNewMenuItem(mmWindowMenu,"x",0);
if (Window->MyMenuItem == NIL)
{
FailurePoint28:
CheckOutDyingWindow(Window->MyGenericWindow);
goto FailurePoint27;
}
if (!RegisterWindowMenuItem(Window->MyMenuItem,(void (*)(void*))&ActivateThisWindow,
Window->ScreenID))
{
FailurePoint29:
KillMenuItem(Window->MyMenuItem);
goto FailurePoint28;
}

Window->NoteState = e4thNote | eDiv1Modifier;
Window->NoteReady = False;
TrackWindowUpdateVScrollBar(Window);
TrackWindowUpdateHScrollBar(Window);
TrackWindowResetButtons(Window);
TrackWindowResetTitlebar(Window);

return Window;
}

Craig Dickson

unread,
Jul 16, 1994, 11:52:35 PM7/16/94
to
In article <30a045$c...@vixen.cso.uiuc.edu>,

Thomas Lawrence <lawr...@cesn2.cen.uiuc.edu> wrote:
|
|The following code must avoid leaking memory.
|
|Can you suggest how to remove the gotos from this function (short of using
|a language with proper exception handling)?
|
|Can you suggest how to 'factor' it into sub-functions meaningfully?

I'll look over this offline and see what I can do.

Ron Mayer

unread,
Jul 16, 1994, 2:12:44 AM7/16/94
to

<2vud6j$5...@wcap.centerline.com> ji...@centerline.com (Jim Frost):


>
> switch (foo) {
> case 1:
> if (bar) {
> case 2:
> /* ... */
> }
> }

Cool!

> I would never have tried that in a million years and was totally
> amazed that it was accepted by every compiler I fed it to.
>
> (This same man wrote a single C statement comprised of ?: statements
> nested forty deep and I don't even remember how many long, rife with
> side-effects. Truly a dizzying intellect.)

Hmm, that doesn't sound to bad to me. I've occasionally done things like

err = tryblue() ? doblue() :
tryred() ? dored() :
tryblack() ? doblack() :
trywhite() ? dowhite() :
trygreen() ? dogreen() :
do_default() ;

and possibly did end up 40 long, and they had side effects. It struck
me as better than the alternatives like:

if (tryblue())
err = doblue();
else if (tryred())
err = dored();
else if (tryblack())
err = doblack();
else if (trywhite())
err = dowhite();
else if (trygreen())
err = dogreen();
else
err = do_default();

or another alternative

int i;
int (*foo[])() = {tryblue,tryred,tryblack,trywhite,trygreen,0};
int (*bar[])() = {doblue,dored,doblack,dowhite,dogreen,0};
for (i=0;(foo[i]!=0);i++)
if (foo[i]()) {
err = bar[i]();
break;
}
if (!foo[i])
err = do_default();


Any better ideas.
IMHO, anyway, "?:" is your friend.

Ron


OBgoto: If you want goto-free C code you can always use longjmp().

Craig Dickson

unread,
Jul 17, 1994, 7:38:11 AM7/17/94
to
|In article <30a045$c...@vixen.cso.uiuc.edu>,
|Thomas Lawrence <lawr...@cesn2.cen.uiuc.edu> wrote:
||
||The following code must avoid leaking memory.
||
||Can you suggest how to remove the gotos from this function (short of using
||a language with proper exception handling)?

Yes.

||Can you suggest how to 'factor' it into sub-functions meaningfully?

Yes.

Your function wants to do several things in the process of creating a
window to be displayed on-screen. Various memory allocations are made,
and various bitmaps loaded. If at any stage of the process there is a
failure, everything done up to that point must be undone so as not
to leak memory, and then a null pointer is returned to the caller.

As written, the function uses a rather clever approach which I must
admit is perhaps the least offensive, yet strangest, use of goto in
C that I have seen. The function is basically organized like this:

step 1
if (failure)
label1:
return null ptr
step 2
if (failure)
label2:
clean up after step 1
goto label1
step3
if (failure)
label 3:
clean up after step 2
goto label2
etc.

Thus, if at any point there is a failure, the code heads into a series
of gotos to clean up exactly what needs cleaning up at that point.

A very straightforward gotoless way of writing such a function is as
follows:

step 1 do each stage, continuing
if (success) to the next if successful
step 2
if (success)
step 3
if (success)
return success everything succeeded; return

clean up after step 2 something failed, so clean
clean up after step 1 up what has already been done
return failure

Now, of course, the indentation would get rather inconvenient in this
particular case, since your code has about 30 stages. As might be
expected by anyone who has been following this thread, my solution,
unless performance requirements dictate otherwise, would be to break
up the function. From a readability/maintainability perspective, this
is a good thing to do anyway, because a 350-line function that does a
lot of work is a clumsy beast that is harder to work with than small
functions that do less work individually. You could, for instance,
have one procedure that creates scroll bars for the window, another
that creates the bitmap buttons, and one that does the administrative
business of checking the new window in and adding a menu entry for it.
If the bitmap buttons can be grouped into categories, they might be
more than one procedure accordingly. Thus you end up with a small
group of reasonably well-defined, reasonably small, well-structured
routines, rather than one 350-line function riddled with gotos. If you
like, all these procedures can be placed in their own source file, with
all the sub-procedures declared 'static' to prevent them from being
called out of context.

Matt Kennel

unread,
Jul 16, 1994, 8:48:32 PM7/16/94
to
Theo Norvell (nor...@comlab.ox.ac.uk) wrote:

: While this particular programmer sounds like a very poor specimen,


: one can also develop the habit of coding all loops with goto's
: for good reasons.

: The while loop is only specific case of recursive procedures and
: it is known that the formal development of programs in terms of
: the more general concept has no drawbacks and often some advantages
: (see "do considered od" by Eric Hehner in Acta Informatica 1979 v11 #4).
: Once you develop the right set of mental habits, the same applies to
: informal program development and program comprehension. If you have a
: tail-recursive procedure that is called (from outside) only once,
: then the most natural way to code it in C or Pascal is to use a
: label and goto(s). A classic example is the 2D array search:
: (var r:=0 ;
: search_from_r :
: if r < N
: then (var c:=0 ;
: search_from_r_c :
: if c < N
: then if suitable( A[r,c] )
: then (Stuff to do when the target is found)
: else (c:=c+1 ; goto search_from_r_c )
: else (r:=r+1 ; goto search_from_r) )
: else (Stuff to do when the target is absent) )
: It is difficult (perhaps impossible) to code this nicely without using
: a goto, procedures, or extra variables.

Well maybe. Or maybe not.

I think what's needed is a whole new idea to encapsulate and make
'user-programmable' the various forms of looping and control structures.

It's probably not the last word, but Sather 1.0 has a pretty nice form
of things called "iters" for situations like this:

loop
loop
if suitable(A[A.inds1!,A.inds2!]) then
-- do something with that element
end;
end;
end;

The expression "A.inds1!" returns successive row indices of array
"A". More likely, you'd just use the "A.elts!" 'iter' which returns
*all* elements of A in some order:

loop
if suitable(A.elts!) then .... end; -- do something
-- with valid elements of A.
end;

My opinion is that it's better to transcend the entire problem rather
than hashing out slightly different alternatives at the same low level.

In Sather the "inds1!" and "elts!" iters are user-written, treated very
similarly to simple routines {take arguments, return values} except they
have special meanings when used inside a loop.

: Theo Norvell

--
-Matt Kennel m...@inls1.ucsd.edu
-Institute for Nonlinear Science, University of California, San Diego
-*** AD: Archive for nonlinear dynamics papers & programs: FTP to
-*** lyapunov.ucsd.edu, username "anonymous".

Olaf Seibert

unread,
Jul 16, 1994, 10:11:51 PM7/16/94
to
In <crdCsu...@netcom.com> c...@netcom.com (Craig Dickson) writes:
>What isn't obvious, though, is how many other places in the function
>jump to that same label. In a small function this doesn't cause a big
>prblem, but in large functions it becomes extremely annoying.

It amazes me that nobody mentioned the great improvement to this problem:
the COME FROM statement! A come from can clearly only come from one
location, so it does not have the drwwaback you mention.

See [Clark 1984] RL Clark: A linguistic contribution to GOTO-less
programming. Communications of the ACM 27 (1984) 349-350, or the
INTERCAL reference manual.

-Olaf.
--
___ Olaf 'Rhialto' Seibert rhi...@mbfys.kun.nl Ooey-Gooey-Fluffy-Barfie
\X/ I'm not weird, I'm differently percepted. D787B44DFC896063 4CBB95A5BD1DAA96

Olaf Seibert

unread,
Jul 16, 1994, 10:16:24 PM7/16/94
to
In <dolf.774097566@alp> do...@echo.tds.philips.nl (Dolf Grunbauer) writes:
>In Algol-68 it is not necessary to write the word GOTO at all, just use
>the label, for example:
>
> GOTO label;
> <code>
>label:<more code>
>
>could also have been written as:
>
> label;
> <code>
>label:<more code>

This was never mentioned in the programming courses, really, but
isn't a label in A68 equivalent to a PROC VOID, so the second example
you give would be a deproceduring of the label (what other languages
call a function call is just a step in the type-conversion process
of A68)?

James Allen

unread,
Jul 18, 1994, 12:56:52 AM7/18/94
to
I too feel the need to followup to the provocative posting by James Allen. :-)

In <ROCKWELL.94...@nova.umd.edu>
rock...@nova.umd.edu (Raul Deluth Miller) writes:
]. #ifdef DONT_USE_GOTO
/* These silly fragments are repeated below*/
]. #else
]. #endif

]Notes:
]
][a] these are not necessarily equivalent [unless Predicate_1 is free
]of side effects].

I mentioned this in the original post and explained why it has no bearing
on the discussion. BTW, side-effects in `Predicate_2' and `foo()' also
render equivalence problematic.

][b] for the cases where they are equivalent, a good optimizing


]compiler should produce the same code for them.

In my posting I stressed that my concern was strictly *readability*;
you may disagree that the second fragment is more readable but don't
claim to disagree with a claim I never made.

But since you bring it up, can you name even *one* "good optimizing
compiler" that produces the same code for the two fragments? I just typed
in a trivial version of the fragment (`Predicate_1' became `i < 10')
and examined the Sparc code produced by Sun's `cc -O4' and FSF's `gcc'.
Neither made any special optimization, although `gcc' produced
...
cmp %l0,9
ble top_of_loop
nop
ble bypass_gargle
nop
call _gargle

(I also tried `gcc -fexpensive-optimizations'; that didn't seem to help.)

][c] another way of writing this [....]
]... just as efficient as the unmodularized original.

This isn't my idiom and I'm trying to make it readable, not efficient.
It occurs constantly in BSD and SunOS source code and it bothers me since
a simpler more readable equivalent exists using `goto.' I *will* mention
that I vastly prefer the BSD idiom to Mr. Miller's "solution" which creates
two new functions wherever the construction arises, presumably to avoid
both `break' and `goto'. (Yes, Mr. Miller mentioned an inlining compiler:
let me repeat myself again --- it is the readability of the source code I
am discussing; the efficiency of the object code is not of interest here.)

In <crdCsz...@netcom.com> c...@netcom.com (Craig Dickson) writes:
]In article <1994Jul15.0...@crc.ricoh.com>,
]James Allen <ja...@crc.ricoh.com> wrote:
]|#ifdef DONT_USE_GOTO


]| for (i = 0; Predicate_1; i++) {
]| foo();
]| if (Predicate_2)
]| break;
]| bar();
]| }
]| if (! Predicate_1)
]| giggle();
]| gargle();
]|#else
]| for (i = 0; Predicate_1; i++) {
]| foo();
]| if (Predicate_2)
]| goto happy_label;
]| bar();
]| }
]| giggle();
]| happy_label:
]| gargle();
]|#endif

]I find both versions slightly brain-damaged. Why not simply:
]
] for (i = 0; Predicate_1; i++) {
] foo();
] if (Predicate_2) {
] giggle();
] break;
] }
] bar();
] }
] gargle();

I think Craig is helping me prove my point! His fragment `giggles()'s only
when the loop terminates prematurely. Both fragments I posted only
`giggle()' when the loop terminates "normally" (falls out after 'bar(), i++,
Predicate_1'). I strongly suspect he developed his fragment by studying the
*first* fragment I posted; the second fragment (with `goto') is quite easy
to follow and Craig wouldn't have had this mental lapse.

]|I think most readers will agree that `break' is also sort of "bad" ---


]|though typically not as "bad" as `goto.'

]No, I have no problems at all with 'break', 'continue', ...
]They cannot act in an arbitrary and structure-violating way as goto can


]and, in practice, usually does.

I'll agree that if the goal is somehow to violate structure then `goto' is
a more powerful weapon than `break'. But just as "Bullets kill, not guns,"
so can we agree that violating structure is the culprit, not `goto?'

]|] if(foo) {bar();} else {baz();}


]|]is more or less equivalent to
]|] if(!foo)goto lab1; bar(); goto lab2; lab1: baz(); lab2:
]|Yes, that's how the C language works. Hmmm, the fact that this wasn't
]|obvious suggests that the anti-goto fanatics have succeeded in brainwashing
]|the younger generation!

]No, it suggests that the person who misread the code doesn't understand


]C very well. It *is* perfectly obvious.

We both agree the unnamed poster had a mental block about this C
construction. My point is that very few people who "believe in goto's"
would have had this mental block --- the subconscious substitution of a
`goto' construction for the `else' makes it all very easy.

]|This is real code that solves a real puzzle, and rather promptly at that.


]|There are several ways to avoid the `goto' but I claim the result would be
]|less efficient and less *readable*.

]You call a two-hundred-line function readable? Puh-leeze.

I do as a matter-of-fact. First of all, I dare say you haven't read many
SCSI device interrupt routines if 200 LOC seems like a long function. :-)
A routine like
foo() {

/* Step 1 -- initialization */
lots_of_lines_of_code();

/* Step 2 -- */
also_lots_of_lines_of_code();

/* Step 3 -- print summary */
many_more_lines_of_code();
}
shouldn't be much harder to grok than:
foo() {
do_step1();
do_step2();
do_step3();
}
do_step1() { lots of stuff }
do_step2() { lots of stuff }
do_step3() { lots of stuff }
the main difference being that ` /* Next step --- */ ' is used to separate
the main pieces instead of ` } /* end of function */
nextfunction() { '
In fact, often the "less factored" code will be *easier* to read.
Just now I browsed through M.I.T.'s `X-client' source-codes which happen to
be online here. I notice that their functions tend to be quite small but
they do include, for example
xterm/main.c:spawn() -- 1001 Lines Of Code
twm/menus.c:ExecuteFunction() -- 799 Lines Of Code
I agree that "Small is Beautiful" and, in hindsight should have edited the
bridge program to avoid this nit but I stand by my earlier injunction:
``Don't be dogmatic.''
It will take the average programmer at least thirty minutes to fully
understand the bridge program. I suspect the complaints about function-size
arose after a one-minute perusal.

The real proof will be how long it actually does take someone to read and
understand the code I posted. But please let's not compare with the speed of
comprehending a sieve-of-Erasthenes 2-liner; compare with another routine
that *efficiently* solves double-dummy (trump) bridge problems.

]|plenty of beef to chomp on --- I bet we'll *all* agree that `goto' is the


]|least of worries with *this* code.)

]True. The fact that the entire program is in main() is the real problem


]with this code. That's why you needed the goto in the first place.

Ignoring comments and empty lines there are 137 lines of code (LOC) in the
`main()' I posted; the routine can be synopsized as:
main()
{
declare 18 local variables; /* 18 LOC */
prompt_for_and_read_input(); /* 33 LOC */
reformat_and_print_problem(); /* 14 LOC */
for(Go_Forward) {} /* 33 LOC */
for(Backtrack) {} /* 26 LOC */
print(solution); /* 12 LOC */
return 0; /* 1 LOC */
}
The version I posted was slightly whimsical (the "real" version has the I/O
sequences encapsulated as small functions) but I don't think it's so very
bad. Most readers will be able to determine quickly that the first 47
executable LOC are simple initializations.

In <ROCKWELL.94...@nova.umd.edu>
rock...@nova.umd.edu (Raul Deluth Miller) writes:
]Second, the particular example of a goto this code presents could


]easily be handled by a return from a subfunction [where there's a loop
]in the subfunction].

Care to have a whack at it? With only 59 LOC in the iterated code and
allowing liberal use of pseudocode it shouldn't be too time-consuming
to demonstrate the alternative. I suspect you'll finish with something
that is *more* clumsy (i.e. less readable) and which does a function call
for *every* attempt to play a card (and hence is significantly slower).

James

Craig Dickson

unread,
Jul 18, 1994, 3:53:33 AM7/18/94
to
In article <1994Jul18.0...@crc.ricoh.com>,
James Allen <ja...@crc.ricoh.com> wrote:

|I think Craig is helping me prove my point! His fragment `giggles()'s only
|when the loop terminates prematurely. Both fragments I posted only
|`giggle()' when the loop terminates "normally" (falls out after 'bar(), i++,
|Predicate_1'). I strongly suspect he developed his fragment by studying the
|*first* fragment I posted; the second fragment (with `goto') is quite easy
|to follow and Craig wouldn't have had this mental lapse.

Actually, I was studying both of them, thinking up different ways of
expressing the logic, and simply got confused somehow. You can see
this in my text, where my analysis is correct up until I write "when
Predicate2 is TRUE" when I ought to have said "FALSE". Of course,
this completely invalidates my counter-example. Oh well!

|]No, I have no problems at all with 'break', 'continue', ...
|]They cannot act in an arbitrary and structure-violating way as goto can
|]and, in practice, usually does.
|
|I'll agree that if the goal is somehow to violate structure then `goto' is
|a more powerful weapon than `break'. But just as "Bullets kill, not guns,"
|so can we agree that violating structure is the culprit, not `goto?'

Yes, but the problem is that goto, in practice, usually does violate
structure. I have known too many coders who habitually used goto in
totally unnecessary, destructive ways. My horror story about the guy
who wrote all his loops using goto is only the worst example.

|]|] if(foo) {bar();} else {baz();}
|]|]is more or less equivalent to
|]|] if(!foo)goto lab1; bar(); goto lab2; lab1: baz(); lab2:
|]|
|]|Yes, that's how the C language works. Hmmm, the fact that this wasn't
|]|obvious suggests that the anti-goto fanatics have succeeded in brainwashing
|]|the younger generation!
|]
|]No, it suggests that the person who misread the code doesn't understand
|]C very well. It *is* perfectly obvious.
|
|We both agree the unnamed poster had a mental block about this C
|construction. My point is that very few people who "believe in goto's"
|would have had this mental block --- the subconscious substitution of a
|`goto' construction for the `else' makes it all very easy.

Understanding what 'if/else' really *means* would do as well. That's the
real issue here, not 'goto'. I would just about be willing to bet money
that that "unnamed poster" does not know any assembly language and has
little understanding of what goes on beneath the surface of an HLL. That
is why he was unable to figure out what would happen when structured
syntax was abused by inserting a 'goto' between an 'if' and an 'else'.

|]|This is real code that solves a real puzzle, and rather promptly at that.
|]|There are several ways to avoid the `goto' but I claim the result would be
|]|less efficient and less *readable*.
|
|]You call a two-hundred-line function readable? Puh-leeze.
|
|I do as a matter-of-fact. First of all, I dare say you haven't read many
|SCSI device interrupt routines if 200 LOC seems like a long function. :-)

I've *written* SCSI device interrupt routines. Two hundred lines in
assembly language is quite different from two hundred lines of C.

|A routine like
| foo() {
|
| /* Step 1 -- initialization */
| lots_of_lines_of_code();
|
| /* Step 2 -- */
| also_lots_of_lines_of_code();
|
| /* Step 3 -- print summary */
| many_more_lines_of_code();
| }
|shouldn't be much harder to grok than:
| foo() {
| do_step1();
| do_step2();
| do_step3();
| }
| do_step1() { lots of stuff }
| do_step2() { lots of stuff }
| do_step3() { lots of stuff }
|the main difference being that ` /* Next step --- */ ' is used to separate
|the main pieces instead of ` } /* end of function */
| nextfunction() { '

Yes, but I note that your first example requires comments to separate the
three sections, whereas in your second example, the language syntax itself
separates the sections. Also, in the real world, the three subprocedures
presumably won't be named 'do_stepX', but should have names that clarify
their purpose. I'm wary of relying on comments to clarify code because
there are a lot of code-whackers out there who don't know how to comment.
(Of course I do comment my code, but the point is that I think it's
better to write the code in a clear, easy-to-grok way to begin with,
rather than rely on comments to clarify a large mass of undifferentiated
code.)

|It will take the average programmer at least thirty minutes to fully
|understand the bridge program. I suspect the complaints about function-size
|arose after a one-minute perusal.

Yes, well, maybe two minutes. :-) However, two minutes with properly
factored code would have been adequate to show me the basic outline
of the algorithm, whereas two minutes of glancing over a large function
whose flow is obscured by goto's is not sufficient. That was the point.

|The real proof will be how long it actually does take someone to read and
|understand the code I posted. But please let's not compare with the speed of
|comprehending a sieve-of-Erasthenes 2-liner; compare with another routine
|that *efficiently* solves double-dummy (trump) bridge problems.

I'm sure we've all seen more than our share of sieve implementations.

|Ignoring comments and empty lines there are 137 lines of code (LOC) in the
|`main()' I posted; the routine can be synopsized as:
| main()
| {
| declare 18 local variables; /* 18 LOC */
| prompt_for_and_read_input(); /* 33 LOC */
| reformat_and_print_problem(); /* 14 LOC */
| for(Go_Forward) {} /* 33 LOC */
| for(Backtrack) {} /* 26 LOC */
| print(solution); /* 12 LOC */
| return 0; /* 1 LOC */
| }

And gosh, look how much easier it is to get a quick, if undetailed,
picture of what the program does when it is expressed this way! The two
for loops would perhaps be in one function, and of course declaring the
local variables wouldn't be a separate function (obviously), but other
than that, you've just factored your code quite nicely; and according to
your numbers, the longest function (the two for loops) would only be
about 60 lines, not bad at all. Why not write it that way?

Jim Frost

unread,
Jul 18, 1994, 10:51:00 AM7/18/94
to
li...@3do.com (Greg Limes) writes:
>In article <2vud6j$5...@wcap.centerline.com>,
>Jim Frost <ji...@centerline.com> wrote:
>>I wouldn't have ever written something like that, and would have sworn
>>it was illegal, but I ran into "production" code with similar
>>constructs written by a man whom I believe to be insane. He basically
>>wrote:
>>
>> switch (foo) {
>> case 1:
>> if (bar) {
>> case 2:
>> /* ... */
>> }
>> }

>You think that is insane? Check this out ...

This particular example was one of the more benign things we ran into.
The thing that convinced me he was insane was a single statement
comprised of ?: statements *nested* forty (40) deep (I don't even know
how many long; it must have been well over a hundred) rife with
side-effects. The single statement more than filled a normal
80-column by 60-line printed page of paper. There were no indentions
or spacings that would show you logical groupings -- it was one solid
chunk of code.

Perhaps he was a genious: nobody else could figure out what that code
was doing. I prefer to think that he was insane.

jim frost
ji...@centerline.com

Jim Frost

unread,
Jul 18, 1994, 10:53:48 AM7/18/94
to
ma...@sono.uucp (Ron Mayer) writes:
><2vud6j$5...@wcap.centerline.com> ji...@centerline.com (Jim Frost):

>> (This same man wrote a single C statement comprised of ?: statements
>> nested forty deep and I don't even remember how many long, rife with
>> side-effects. Truly a dizzying intellect.)

>Hmm, that doesn't sound to bad to me. I've occasionally done things like

> err = tryblue() ? doblue() :
> tryred() ? dored() :
> tryblack() ? doblack() :
> trywhite() ? dowhite() :
> trygreen() ? dogreen() :
> do_default() ;

>and possibly did end up 40 long, and they had side effects.

This is a simple construct in comparison, no matter how long you
chain it. I really wish I could post the code fragment I was talking
about because you simply can't believe it until you see it. I still
have a hard time believing it and I was there at the time.

jim frost
ji...@centerline.com

Herman Rubin

unread,
Jul 18, 1994, 10:44:43 AM7/18/94
to
In article <crdCt4...@netcom.com> c...@netcom.com (Craig Dickson) writes:
>In article <1994Jul18.0...@crc.ricoh.com>,
>James Allen <ja...@crc.ricoh.com> wrote:
>
>|I think Craig is helping me prove my point! His fragment `giggles()'s only
>|when the loop terminates prematurely. Both fragments I posted only
>|`giggle()' when the loop terminates "normally" (falls out after 'bar(), i++,
>|Predicate_1'). I strongly suspect he developed his fragment by studying the
>|*first* fragment I posted; the second fragment (with `goto') is quite easy
>|to follow and Craig wouldn't have had this mental lapse.

>Actually, I was studying both of them, thinking up different ways of
>expressing the logic, and simply got confused somehow. You can see
>this in my text, where my analysis is correct up until I write "when
>Predicate2 is TRUE" when I ought to have said "FALSE". Of course,
>this completely invalidates my counter-example. Oh well!
>
>|]No, I have no problems at all with 'break', 'continue', ...
>|]They cannot act in an arbitrary and structure-violating way as goto can
>|]and, in practice, usually does.
>|
>|I'll agree that if the goal is somehow to violate structure then `goto' is
>|a more powerful weapon than `break'. But just as "Bullets kill, not guns,"
>|so can we agree that violating structure is the culprit, not `goto?'
>
>Yes, but the problem is that goto, in practice, usually does violate
>structure. I have known too many coders who habitually used goto in
>totally unnecessary, destructive ways. My horror story about the guy
>who wrote all his loops using goto is only the worst example.

Here is an actual type of example, not constructed for the purpose.

There is a natural program, which at various places enters what is,
in effect, a state machine. If is also the case that the lower
number states are more common, and that state 1 is an exit.

So let us first look at the goto-less code, if anything designed for
efficiency.

At various places, one evaluates the state number and puts in the code

state_machine(state_number);

When it comes to the state machine, and pardon C errors here:

switch (state_number)

case 1: exit;

case 2: ............
state_number = 1;
break;

case 3: .........
if(condition)state_number=1;
else state_number=2;
break;

..............................

Now let us look at the goto version.

At each point where the state machine is called, the state number is known.
There are other items, besides the state number, which go into the state
machine.

We can use the following code:

At various places, if the state number is > 5, one produces

state_number = .,,;
goto case_high;

if it is not,

goto case_...;

where the state number determines the label.

The analog of the state machine code becomes

case_high: ....

case_5: ...

case_4: ...

case_3: ...

case_2: ...

case_1: final treatment;

Each of these sections of code itself involves gotos.

Frankly, I doubt that the goto code will be harder to understand than
the one without gotos, nor much harder to maintain.

Nor do I believe that a compiler can produce the more efficient code.

There is another advantage. In some cases, the other information can
be used to replace the simple code above with short code which does what
the state machine does without requiring the state machine to carry out
the comparisons involved; this code is loaded with comparisons, and they
are essential, as the items being processed are random bits and related
pieces of information.

--
Herman Rubin, Dept. of Statistics, Purdue Univ., West Lafayette IN47907-1399
Phone: (317)494-6054
hru...@stat.purdue.edu (Internet, bitnet)
{purdue,pur-ee}!snap.stat!hrubin(UUCP)

Herman Rubin

unread,
Jul 18, 1994, 10:51:57 AM7/18/94
to

How about the goto idea, if the type of error is known. This is not
always the case, but it may be that one could produce, at the points
where an error can occur,

goto err_type;

and at later

err_type: err = do_type();

This may not always be as easy to set up, and may involve other
partial procedures, but if it can be done, it is far faster, and
just as easy to understand.

>IMHO, anyway, "?:" is your friend.
>
> Ron
>
>
>OBgoto: If you want goto-free C code you can always use longjmp().

John Morris

unread,
Jul 17, 1994, 7:50:59 PM7/17/94
to
[all previous arguments read with interest. This doesn't really follow
on directly from any, but is a new threadlet . . . ]

There are cases when a goto really is, not just desirable, but
*highly* desirable!

I am thinking of a Z80 emulator I wrote for the VAX, some years ago (VMS
version 3.1 - that should date it). It did eventually get cp/m up and
running too!

The main emulation loop was something like:

for (;;)
{
switch (memory[pc++])
{
case 0x00:
/* emulate whatever that was */
break;

case 0xnn
/* and so on.... */

}

That was fine - but how to get out of it? I wanted to embed illegal
opcodes which could be used to cause a trap to the emulator program to
do special things - such as terminating the program. In the first cut I
modified the main loop to something like:

for (done = 0; !done; )
{
switch (mem[pc++])
{
/* blah blah blah */

case 0xAN_ILLEGAL_INSTRUCTION_I_USE_FOR_TERMIATION:
done = 1;
break

/* . and so on . */

The trouble was that pesky test of "done" - performed for every
emulated opcode, but only firing once in a few million iterations.

Changing the loop to use a goto in the appropriate case clause gave a
speed improvment of (mumble my memory isn't what it used to be etc)
around 25%.

Maybe a smarter compiler could have done this for me - but 25% on an
11/750 was worth having.


--
John Morris email: Jo...@kirsta.demon.co.uk AX25: GM4ANB@GB7EDN.#77.GBR.EU

Jim Frost

unread,
Jul 18, 1994, 4:42:45 PM7/18/94
to
rhi...@mbfys.kun.nl (Olaf Seibert) writes:
>In <crdCsu...@netcom.com> c...@netcom.com (Craig Dickson) writes:
>>What isn't obvious, though, is how many other places in the function
>>jump to that same label. In a small function this doesn't cause a big
>>prblem, but in large functions it becomes extremely annoying.

>It amazes me that nobody mentioned the great improvement to this problem:
>the COME FROM statement! A come from can clearly only come from one
>location, so it does not have the drwwaback you mention.

>See [Clark 1984] RL Clark: A linguistic contribution to GOTO-less
>programming. Communications of the ACM 27 (1984) 349-350, or the
>INTERCAL reference manual.

Oh God, the last thing we need is INTERCAL influences :-).

What amazes me is that someone would find it so difficult to search
for instances of "goto labelname" to find all the targets. It works
for me.

jim frost
ji...@centerline.com

Nevin Liber

unread,
Jul 18, 1994, 8:15:21 PM7/18/94
to
In article <crdCsy...@netcom.com>, Craig Dickson <c...@netcom.com> wrote:

>In the real world, you don't know whether the code will be well maintained
>or not. Most likely it will not be, because the average peron-who-gets-paid-
>to-write-code is not very good.

I'd attribute this more to it being because typically the people who
are doing code maintenance are inexperienced (fresh out of college, new
to the project at hand, new to working on someone else's code, new to
working on code that has a lifetime of more than one semester, new to
working on code that has to be useable in the next version of the
product, etc.).

No matter how careful the original programmer who put in the GOTO was
in placing it in the code, the message given to the newbie is that
GOTOs are ok, anytime, anyplace. Even if you document why it is there,
and that it should be the exception, not the rule, the message is still
that GOTOs are ok, anytime, anyplace, as long as you have a reason.
And as this person moves on to do development, which is where the
issues of code maintainability are prevalent, they may still be working
under this false assumption.

For those folks who have occasionally used GOTOs, how well did you
document the tradeoffs and considerations you thought about before
putting it in the code? Is your documentation adequate to get the
person inheriting and learning from your code to also think about these
issues before modifying your code or putting a GOTO into other code?
If possible, could you post this existing documentation, so that we may
all benefit?


The job of people doing code maintenance is to fix bugs / add features
without adversely affecting the rest of their project; ie, bug for bug
compatibility with everything except what they are fixing. This goal
opposes keeping the code maintainable. Over time, this means that the
code tends to get worse as time goes on (and I used to just think that
it was bit rot :-)). The code maintenance cycle typically begins somewhere
between just before alpha 'til late beta. At this time, you no longer
get the luxury of rewriting code to make it better, more robust, etc.
If you are a commercial company, it is more important at this point to
get the product out the door than to delay to make things better for the
mainenance done months down the road.

Rewriting existing, mostly working code can be deadly for a project.
It is nearly impossible to figure out all the undocumented side effects
that a given function might have that other parts of the system are
dependent upon.

True example: someone had written a routine to pick an unused uid for
a Unix system, for use in creating a new user. The comments for the code
said that a bitmap was made of the uids in /etc/passwd, and that the lowest
unused uid was returned. The code itself picked a random number, checked
to see if it was used, and if not, returned that number. There was a bug
in this code. I, being new, decided to rewrite this code to match the
comment, since I thought that it was a more elegant solution. I compiled
and tested my fix, and it worked fine. I checked the code in, and thought
I was done. When I returned to work the next day, someone came over to my
office to tell me that I broke the system; a critical piece of code was
now in an infinite loop. Since he was working on something which had
nothing to do with uids, I thought this kind of strange. What happened?
It turns out someone was calling this routine twice in a row to get two
different random numbers. <sigh>


Writing maintainable code *is* the resposibility of the original
developers of that code. You can't use the excuse that since the
code will eventually become a mess of spaghetti anyway, that it isn't
an important goal initially. Just think: you may get stuck having to
maintain code written by someone just like you. :-)
--
Nevin ":-)" Liber ne...@cs.arizona.edu (602) 293-2799
+++ (520) after 3/95
summer office: (602) 621-8112
Only 25 more shopping days 'til my birthday (August 12th)!!

Scott E Gilbert

unread,
Jul 18, 1994, 9:12:32 PM7/18/94
to
In article <30e4sk$4...@wcap.centerline.com>,
Jim Frost <ji...@centerline.com> wrote:

[snip snip sniparoo]

>
>This particular example was one of the more benign things we ran into.
>The thing that convinced me he was insane was a single statement
>comprised of ?: statements *nested* forty (40) deep (I don't even know
>how many long; it must have been well over a hundred) rife with
>side-effects. The single statement more than filled a normal
>80-column by 60-line printed page of paper. There were no indentions
>or spacings that would show you logical groupings -- it was one solid
>chunk of code.
>
>Perhaps he was a genious: nobody else could figure out what that code
>was doing. I prefer to think that he was insane.
>
>jim frost
>ji...@centerline.com


Could you post this piece of code? I once had a friend who described the ?:
operator as the ``bane of all clear coding''. Personally I really like it.
Especialy in situations like:

switch( (a < 0) ? 'A' :
(a < 20) ? 'B' :
(a < 45) ? 'C' :
(a < 100)? 'D' :
...
...
'Z' ){
case 'A':
...
break;
case 'B':
...
break;

}


Which I think is much clearer to read than:

switch(a){
case -20: case -19: case -18: case -17 case -16:
case -15: ....
case 0:
what_I_actually_wanted_to_do();
break;
case 1: case 2: case 3: case 4: case I get sick:...
}


With this huge religious/philosophical discussion of the usage of goto, I am
mildly curious what people think of constructs like those above.

--
\\======= Scott Gilbert ========\\
\\ sc...@caslon.cs.arizona.edu \\
\\ sc...@gas.uug.arizona.edu \\
\\==============================\\

Buddha Buck

unread,
Jul 18, 1994, 9:45:21 PM7/18/94
to
In article <1994Jul18.0...@crc.ricoh.com>,

James Allen <ja...@crc.ricoh.com> wrote:
>]|] if(foo) {bar();} else {baz();}
>]|]is more or less equivalent to
>]|] if(!foo)goto lab1; bar(); goto lab2; lab1: baz(); lab2:
>]|Yes, that's how the C language works. Hmmm, the fact that this wasn't
>]|obvious suggests that the anti-goto fanatics have succeeded in brainwashing
>]|the younger generation!
>]No, it suggests that the person who misread the code doesn't understand
>]C very well. It *is* perfectly obvious.
>
>We both agree the unnamed poster had a mental block about this C
>construction. My point is that very few people who "believe in goto's"
>would have had this mental block --- the subconscious substitution of a
>`goto' construction for the `else' makes it all very easy.

As I think I am the "unnamed poster" (the "explanation" of how if-else
works was in response to one of my posts), I'd like to speak in my
defence...

In the original example which I was questioning, there was an implicit
goto (using a switch statement) to the inside of a if-else (to the if
clause, bypassing the test). My question had more to do with the
semantics of this dubious construct than with the semantics of
if-else. The answer is that if the if-clause is executed, the
else-clause is not, regardless of how the if-clause was entered.

I started coding in BASIC and assembly, so I am familiar with goto,
it's abuses and proper uses.

>In <ROCKWELL.94...@nova.umd.edu>
> rock...@nova.umd.edu (Raul Deluth Miller) writes:
>]Second, the particular example of a goto this code presents could
>]easily be handled by a return from a subfunction [where there's a loop
>]in the subfunction].
>
>Care to have a whack at it? With only 59 LOC in the iterated code and
>allowing liberal use of pseudocode it shouldn't be too time-consuming
>to demonstrate the alternative. I suspect you'll finish with something
>that is *more* clumsy (i.e. less readable) and which does a function call
>for *every* attempt to play a card (and hence is significantly slower).
>

I bet he specifies that his subfunction will be an inline function,
thus geting around the performance bottleneck of doing a function call
for each attempt to play a card.

Of course, I could point out that in most cases, an exceptional return
from an inlined function is equivilant to a goto, so if goto's are
bad, then so are exceptional returns from inlined functions!

>James


--
bb...@nox.cs.du.edu # http://nyx10.cs.du.edu:8001/~bbuck/home.html
Buddha Buck #
85.5 Albany Street # The above opinions are mine, MINE, MINE!!!
Cazenovia, NY 13035 # and you can't have them! So there!

Nevin Liber

unread,
Jul 18, 1994, 9:59:06 PM7/18/94
to
In article <Ct54y...@mozo.cc.purdue.edu>,

our buddy Herman Rubin <hru...@b.stat.purdue.edu> wrote:

>Here is an actual type of example, not constructed for the purpose.

>So let us first look at the goto-less code, if anything designed for
>efficiency.

Herman, we weren't talking about *absolute* efficiency, which is about
all you ever talk about. We were talking about code *maintainability*
and *reasonable* efficiency. This is an engineering *tradeoff*, which
we have to make, because, unlike you, our time is valuable. Since your
time is worthless with respect to machine cycles, this is a tradeoff
that you never consider. We've all seen your spaghetti C code with GOTOs
(and I am not implying that it is spaghetti code because there are GOTOs in
it) on this forum (well, comp.lang.misc anyway) before; I know with
certainty that you've never considered anything but absolute
efficiency with respect to some simplistic notions and wrong
assumptions on how existing computer systems work (you always
*convienently* ignore stuff like paging, waiting for I/O, other stuff
running on the machine, working set size etc., when you rant and rave about
efficiency of code, but I digress).

The GOTO-less state machine you describe is done that way because it is
fairly easy to maintain and reasonably efficient.


>When it comes to the state machine, and pardon C errors here:

Why should we pardon C errors?? I thought you said:

>Here is an actual type of example, not constructed for the purpose.

If it's an actual type of example, why aren't you even sure that it
will compile?? Quit lying to us. It *is* an example constructed for the
purpose of this discussion.

I've noticed that you never seem to *ever* post code that compiles
right off the bat. Do you do any actual coding? Does your stuff ever
work?? I know, I know, you would rather have theoretically fast
theoretical code than working correct code which produces useful
results, and whine about how we don't give you tools to write
theoretically fast theoretical code.

[code for a state machine in C using a switch statement on the state
deleted]

>The analog of the state machine code becomes

>case_high: ....

>case_5: ...

>case_4: ...

>case_3: ...

>case_2: ...

>case_1: final treatment;

>Each of these sections of code itself involves gotos.

>Frankly, I doubt that the goto code will be harder to understand than
>the one without gotos, nor much harder to maintain.

If you would post a real example of working code that implements this,
we could tell you. At least everybody else involved in this discussion
posted code that in some form or another exists and is in use. One
can't make tradeoffs based on contrived, incomplete examples, and
expect them to apply to other situations. Is it so much to ask to have
you, a self-proclaimed expert on this subject, to post real, existing,
robust, working code??

>Nor do I believe that a compiler can produce the more efficient code.

What you believe or don't believe is irrelevant. You claim to be a
mathematician. Tell us what is *theoretically* different between the
switch method and the GOTO method. What would stop someone from
writing a source to source translator changing the switch method to the
GOTO method? If you can't tell us what makes this impossible, then how
come you don't believe that it is possible to put this optimisation
into a compiler (if indeed it is an optimisation; you've kind of waved
your hands and want us to believe that this is more efficient code.
Where are your actual *statistics* to back this up??). Do you have some
problem understanding logic, derivations, or proofs?? Either the
switch method is equivalent to the GOTO method, or it is not. If it
is not, then please, please show us where it is different. If it is,
then where is the flaw in my reasoning that this optimisation (if
indeed it is one) is possible? Please, Herman, straighten me out on
this!

>There is another advantage. In some cases, the other information can
>be used to replace the simple code above with short code which does what
>the state machine does without requiring the state machine to carry out
>the comparisons involved; this code is loaded with comparisons, and they
>are essential, as the items being processed are random bits and related
>pieces of information.

In other words, by adding more states to the state machine, you can
have less code and data within each state (and vice versa, which as
best as I can parse the above paragraph, is what you stated Herman).
Of course, anybody who has ever actually coded up a state machine
already understands this classic tradeoff. You have to store the
information somewhere; either implicitly stored in the state, or
explicitly stored at some memory location.

What you haven't told us is why this is not possible (heck, I'd settle
for not trivial) using the switch method given your own assumption that
it is possible with the GOTO method. Herman Rubin, why isn't it possible
using a switch statement??

Buddha Buck

unread,
Jul 18, 1994, 10:01:01 PM7/18/94
to
In article <crdCt4...@netcom.com>, Craig Dickson <c...@netcom.com> wrote:
>In article <1994Jul18.0...@crc.ricoh.com>,
>James Allen <ja...@crc.ricoh.com> wrote:
>
>|]|] if(foo) {bar();} else {baz();}
>|]|]is more or less equivalent to
>|]|] if(!foo)goto lab1; bar(); goto lab2; lab1: baz(); lab2:
>|]|
>|]|Yes, that's how the C language works. Hmmm, the fact that this wasn't
>|]|obvious suggests that the anti-goto fanatics have succeeded in brainwashing
>|]|the younger generation!
>|]
>|]No, it suggests that the person who misread the code doesn't understand
>|]C very well. It *is* perfectly obvious.
>|
>|We both agree the unnamed poster had a mental block about this C
>|construction. My point is that very few people who "believe in goto's"
>|would have had this mental block --- the subconscious substitution of a
>|`goto' construction for the `else' makes it all very easy.
>
>Understanding what 'if/else' really *means* would do as well. That's the
>real issue here, not 'goto'. I would just about be willing to bet money
>that that "unnamed poster" does not know any assembly language and has
>little understanding of what goes on beneath the surface of an HLL. That
>is why he was unable to figure out what would happen when structured
>syntax was abused by inserting a 'goto' between an 'if' and an 'else'.

I apparantly am the "unnamed poster". The problem I had was a real
stupid thinko. I know switch sematics as "without a break, case
clauses fall through". In this case, this semantic conflicted with
the semantics for if/else. It was a thinko.

BTW, you would lose your money. I started by doing BASIC programming,
and have done assembly for 8080, 8088, 6502, 8031 and VAX. It was the
abuse of the switch statement which confused me, not the if/else.

>--
>Craig Dickson (c...@netcom.com): a collector and cataloger of net.butterflies.
>KotM archives, a.u.k FAQ, and Net.Legends FAQ: ftp://ftp.netcom.com/pub/crd.
>Whish! A gull. Gulls. Far calls. Coming, far! End here. Us then. Finn, again!
>"Inscrutable people tend to drink inscrutable beer." -- Elizabeth of Windsor.

Miguel Carrasquer

unread,
Jul 18, 1994, 10:45:13 PM7/18/94
to
In article <30f9a0$g...@caslon.CS.Arizona.EDU>,
Scott E Gilbert <sc...@CS.Arizona.EDU> wrote:
>... I once had a friend who described the ?:

I really like it! I'm sure to try it out the next time stuff
like this comes up in my code. It sure beats writing out all the
different cases, or putting the tests in the default case, which is
what I normally do.

--
Miguel Carrasquer ____________________ ~~~
Amsterdam [ ||]~
m...@inter.NL.net ce .sig n'est pas une .cig

Matt Francomb

unread,
Jul 18, 1994, 5:39:14 AM7/18/94
to
In article <crdCsx...@netcom.com> c...@netcom.com (Craig Dickson) writes:
In article <1994Jul13.2...@client11.comlab.ox.ac.uk>,
Theo Norvell <nor...@comlab.ox.ac.uk> wrote:
[....]

| (var r:=0 ;
| search_from_r :
| if r < N
| then (var c:=0 ;
| search_from_r_c :
| if c < N
| then if suitable( A[r,c] )
| then (Stuff to do when the target is found)
| else (c:=c+1 ; goto search_from_r_c )
| else (r:=r+1 ; goto search_from_r) )
| else (Stuff to do when the target is absent) )
|It is difficult (perhaps impossible) to code this nicely without using
|a goto, procedures, or extra variables.

Want to bet?

void ScanArray2D(<type> *A, int N)
{
int r, c;

for (r = 0; r < N; r++)
for (c = 0; c < N; c++)
if (suitable(A[r][c]))
{
// stuff to do when the target is found goes here
return;
}

// stuff to do when the target is absent goes here
}

Now, of course, I'm using a reasonable language (C), whereas your
example is in an unreasonable one (Pascal), but even so, I think
my point is made...

Ahem. That may be an unreasonable language (although it looks OK to
me apart from all the extra parentheses and lack of types in variable
declarations), but one thing it *ain't* is Pascal. The gotos sure make it
hard to read, though. The fact that C (along with a lot of other more
useable languages, including UCSD Pascal, which calls it "exit") has a
"return" statement doesn't make it reasonable. (Perhaps you should
learn Pascal - it doesn't take very long).

Try:

TYPE T = ...;

PROCEDURE Scan2dArray (A: ARRAY OF ARRAY OF T);
VAR r, c: CARDINAL;
BEGIN
FOR r := 0 TO HIGH (A) DO
FOR c := 0 TO HIGH (A[r]) DO
IF Suitable (A[r, c]) THEN
DoStuffWhenTargetPresent (A, r, c);
RETURN
END
END
END;
DoStuffWhenTargetAbsent;
END Scan2dArray;

Which even avoids the use of the unnecessary argument N and isn't
limited to square matrices and doesn't have a goto (because the
language used doesn't provide one).
--
Matt Francomb, Setanta Software Ltd: ma...@setanta.demon.co.uk

Alan Watson

unread,
Jul 19, 1994, 1:29:00 AM7/19/94
to

I think it's so bad that you must have posted it as a joke. It has not
even a single redeeming quality. Either use a simple if/else chain:

if (a < 0)
...
else if (a < 20)
...

or, if the case labels actually mean something, bundle the if/else
chain in a function and use:

switch (convert_to_a_letter_that_actually_means_something(a)) {


case 'A':
...
break;
case 'B':
...
break;

...
}

In this case, though, the case labels should perhaps be #defined
constants or enumeration values with meaningful names.

--
Alan Watson | ``Make `i' a register variable, please,
al...@oldp.astro.wisc.edu | HAL.'' ``I'm sorry, Dave. I'm afraid I
Department of Astronomy | can't do that.''
University of Wisconsin -- Madison | -- Neil Gall

Message has been deleted
It is loading more messages.
0 new messages