By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
440,928 Members | 1,146 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 440,928 IT Pros & Developers. It's quick & easy.

What do you think about the code?

P: n/a
Can you give any comments on this code?
I used one goto, is it bad?

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <assert.h>

#define NOT_NULL 1
#define NUMERIC 2
#define MULTI_LINE 4

/* Describes one field of a record */
struct field_desc {
char *name;
int length;
int type;
};

#define FIELD_PROMPT "%s (%d): "

struct record {
size_t count;
struct field_desc *desc;
char **entries;
};

struct field_desc movies_desc[] = {
{ "id", 13, NOT_NULL | NUMERIC },
{ "title", 50, NOT_NULL },
{ "genre", 15, NOT_NULL },
{ "length", 3, NOT_NULL | NUMERIC },
{ "description", 65535, MULTI_LINE },
{ "owner", 10, NOT_NULL },
{ "available", 1, NOT_NULL | NUMERIC },
{ "customer", 30, 0 } };

#define MOVIES_LENGTH (sizeof(movies_desc)/sizeof(movies_desc[0]))

char *readl(size_t length, int multiline, char stop)
{
const size_t bufsize = 32;
int c, lastc;
size_t index;
size_t size;
char *str, *tmp;

size = 0;
str = NULL;

if (multiline)
lastc = '\n';
else
lastc = 0;

index = 0;
while ((c = getchar()) != EOF && index < length) {
if (index + 1 >= size) {
size += bufsize;
if (size > length + 1)
size = length + 1;

tmp = realloc(str, size);
if (tmp == NULL) {
if (str)
free(str);
return NULL;
}
str = tmp;
}

/* Will only be true if multiline */
if (c == stop && lastc == '\n') {
if (stop == '\n')
break;
if ((c = getchar()) == '\n' || c == EOF)
break;
else {
ungetc(c, stdin);
c = stop;
}
}
if (c == '\n' && !multiline)
break;

assert(index + 1 < size);
str[index++] = c;
lastc = c;
}
if (c == EOF && index == 0)
return NULL;

assert(str != NULL);
assert(index < size);
str[index] = '\0';

/* Remove trailing '\n's (multiline only) */
if (index != 0 && lastc == '\n')
str[index - 1] = '\0';

/* Remove remaining characters on the line. */
while(c != '\n' && c != EOF)
c = getchar();

return str;
}

/* This function assumes sticky eof. That means,
* if an EOF is encountered, it will be read again
* from getchar() at the next call to this function. */
char *read_multiline(size_t length)
{
return readl(length, 1, '\n');
}

/* Reads one line of max length and discards additional
* characters on the line. Intended for interactive use */
char *read_line(size_t length)
{
return readl(length, 0, 0);
}

int isnumeric(const char *str)
{
if (!str)
return 0;
while (*str) {
if (!isdigit(*str) && *str != '\n')
return 0;
str++;
}
return 1;
}

static int validate_entry(const char *entry, struct field_desc desc)
{
if ((desc.type & NUMERIC) && !isnumeric(entry)) {
fprintf(stderr, "Error: Value must be numeric\n");
return -1;
}
if ((desc.type & NOT_NULL) && entry[0] == '\0') {
fprintf(stderr, "Error: Value must not be null\n");
return -1;
}

return 0;
}

static void field_prompt(struct field_desc desc)
{
printf(FIELD_PROMPT, desc.name, desc.length);
fflush(stdout);
}

static int get_field(char **entry, struct field_desc desc)
{
if (desc.type & MULTI_LINE)
*entry = read_multiline(desc.length);
else
*entry = read_line(desc.length);

if (*entry == NULL)
return EOF;

return 0;
}

int set_record_type(struct record *r, struct field_desc *desc, size_t
length)
{
size_t i;
r->count = length;
r->desc = desc;
r->entries = malloc(length * sizeof(char *));
if (r->entries == NULL)
return -1;
/* Init all data to NULL */
for (i = 0; i < length; i++)
r->entries[i] = NULL;
return 0;
}

/* Fills record with input from user */
int fill_record(struct record r)
{
size_t i;
for (i = 0; i < r.count; i++) {

field_prompt(r.desc[i]);
if (get_field(&r.entries[i], r.desc[i]) == EOF)
goto atEOF;

while (validate_entry(r.entries[i], r.desc[i]) != 0) {
free(r.entries[i]);
field_prompt(r.desc[i]);
if (get_field(&r.entries[i], r.desc[i]) == EOF)
goto atEOF;
}
}

return 0;

atEOF:
while (i--) {
free(r.entries[i]);
r.entries[i] = NULL;
}
return EOF;
}

void print_record(struct record r)
{
size_t i;
for (i = 0; i < r.count; i++) {
printf("%s:\"%s\"\n", r.desc[i].name, r.entries[i]);
}
}

void free_record(struct record r)
{
size_t i;

for (i = 0; i < r.count; i++) {
if (r.entries[i])
free(r.entries[i]);
}
free(r.entries);
}

int main(void)
{
struct record movies_record;

set_record_type(&movies_record, movies_desc, MOVIES_LENGTH);

fill_record(movies_record);

print_record(movies_record);

free_record(movies_record);

return EXIT_SUCCESS;
}
Jun 22 '06 #1
Share this Question
Share on Google+
53 Replies


P: n/a
jaso wrote:

Can you give any comments on this code?
I used one goto, is it bad?


It's not very bad.

--
pete
Jun 23 '06 #2

P: n/a
you can write any code that uses a goto, without a goto.

Goto is disliked, as it leads to code that is harder to read. You
should try to eliminate goto's as it will make somebody(other then you)
able to edit your code.
jaso wrote:
Can you give any comments on this code?
I used one goto, is it bad?

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <assert.h>

#define NOT_NULL 1
#define NUMERIC 2
#define MULTI_LINE 4

/* Describes one field of a record */
struct field_desc {
char *name;
int length;
int type;
};

#define FIELD_PROMPT "%s (%d): "

struct record {
size_t count;
struct field_desc *desc;
char **entries;
};

struct field_desc movies_desc[] = {
{ "id", 13, NOT_NULL | NUMERIC },
{ "title", 50, NOT_NULL },
{ "genre", 15, NOT_NULL },
{ "length", 3, NOT_NULL | NUMERIC },
{ "description", 65535, MULTI_LINE },
{ "owner", 10, NOT_NULL },
{ "available", 1, NOT_NULL | NUMERIC },
{ "customer", 30, 0 } };

#define MOVIES_LENGTH (sizeof(movies_desc)/sizeof(movies_desc[0]))

char *readl(size_t length, int multiline, char stop)
{
const size_t bufsize = 32;
int c, lastc;
size_t index;
size_t size;
char *str, *tmp;

size = 0;
str = NULL;

if (multiline)
lastc = '\n';
else
lastc = 0;

index = 0;
while ((c = getchar()) != EOF && index < length) {
if (index + 1 >= size) {
size += bufsize;
if (size > length + 1)
size = length + 1;

tmp = realloc(str, size);
if (tmp == NULL) {
if (str)
free(str);
return NULL;
}
str = tmp;
}

/* Will only be true if multiline */
if (c == stop && lastc == '\n') {
if (stop == '\n')
break;
if ((c = getchar()) == '\n' || c == EOF)
break;
else {
ungetc(c, stdin);
c = stop;
}
}
if (c == '\n' && !multiline)
break;

assert(index + 1 < size);
str[index++] = c;
lastc = c;
}
if (c == EOF && index == 0)
return NULL;

assert(str != NULL);
assert(index < size);
str[index] = '\0';

/* Remove trailing '\n's (multiline only) */
if (index != 0 && lastc == '\n')
str[index - 1] = '\0';

/* Remove remaining characters on the line. */
while(c != '\n' && c != EOF)
c = getchar();

return str;
}

/* This function assumes sticky eof. That means,
* if an EOF is encountered, it will be read again
* from getchar() at the next call to this function. */
char *read_multiline(size_t length)
{
return readl(length, 1, '\n');
}

/* Reads one line of max length and discards additional
* characters on the line. Intended for interactive use */
char *read_line(size_t length)
{
return readl(length, 0, 0);
}

int isnumeric(const char *str)
{
if (!str)
return 0;
while (*str) {
if (!isdigit(*str) && *str != '\n')
return 0;
str++;
}
return 1;
}

static int validate_entry(const char *entry, struct field_desc desc)
{
if ((desc.type & NUMERIC) && !isnumeric(entry)) {
fprintf(stderr, "Error: Value must be numeric\n");
return -1;
}
if ((desc.type & NOT_NULL) && entry[0] == '\0') {
fprintf(stderr, "Error: Value must not be null\n");
return -1;
}

return 0;
}

static void field_prompt(struct field_desc desc)
{
printf(FIELD_PROMPT, desc.name, desc.length);
fflush(stdout);
}

static int get_field(char **entry, struct field_desc desc)
{
if (desc.type & MULTI_LINE)
*entry = read_multiline(desc.length);
else
*entry = read_line(desc.length);

if (*entry == NULL)
return EOF;

return 0;
}

int set_record_type(struct record *r, struct field_desc *desc, size_t
length)
{
size_t i;
r->count = length;
r->desc = desc;
r->entries = malloc(length * sizeof(char *));
if (r->entries == NULL)
return -1;
/* Init all data to NULL */
for (i = 0; i < length; i++)
r->entries[i] = NULL;
return 0;
}

/* Fills record with input from user */
int fill_record(struct record r)
{
size_t i;
for (i = 0; i < r.count; i++) {

field_prompt(r.desc[i]);
if (get_field(&r.entries[i], r.desc[i]) == EOF)
goto atEOF;

while (validate_entry(r.entries[i], r.desc[i]) != 0) {
free(r.entries[i]);
field_prompt(r.desc[i]);
if (get_field(&r.entries[i], r.desc[i]) == EOF)
goto atEOF;
}
}

return 0;

atEOF:
while (i--) {
free(r.entries[i]);
r.entries[i] = NULL;
}
return EOF;
}

void print_record(struct record r)
{
size_t i;
for (i = 0; i < r.count; i++) {
printf("%s:\"%s\"\n", r.desc[i].name, r.entries[i]);
}
}

void free_record(struct record r)
{
size_t i;

for (i = 0; i < r.count; i++) {
if (r.entries[i])
free(r.entries[i]);
}
free(r.entries);
}

int main(void)
{
struct record movies_record;

set_record_type(&movies_record, movies_desc, MOVIES_LENGTH);

fill_record(movies_record);

print_record(movies_record);

free_record(movies_record);

return EXIT_SUCCESS;
}


Jun 23 '06 #3

P: n/a
On 2006-06-23, mi********@gmail.com <mi********@gmail.com> wrote:
you can write any code that uses a goto, without a goto.

Goto is disliked, as it leads to code that is harder to read. You
should try to eliminate goto's as it will make somebody(other then you)
able to edit your code.


Don't top-post. I've eliminated what you quoted because it isn't really
relevant to your point.

What is easier to read:
/* Start */

while (test[0])
while (test[1])
while (test[2])
{
if (test[3])
goto outOfLoop;
}

outOfLoop:
puts ("Escaped from loop.");
/* End */

Or, without goto:

/* Start */

int status = 0;

while (test[0])
{
while (test[1])
{
while (test[2])
{
if (test[3])
{
status = 1;
break;
}
}
if (status)
break;
}
if (status)
break;
}

puts ("Escaped from loop.");

/* End */

--
Andrew Poelstra < http://www.wpsoftware.net/blog >
To email me, use "apoelstra" at the above address.
I know that area of town like the back of my head.
Jun 23 '06 #4

P: n/a
Andrew Poelstra wrote:

What is easier to read:
/* Start */

while (test[0])
while (test[1])
while (test[2])
{
if (test[3])
goto outOfLoop;
}

outOfLoop:
puts ("Escaped from loop.");
/* End */

Or, without goto:

/* Start */

int status = 0;

while (test[0])
{
while (test[1])
{
while (test[2])
{
if (test[3])
{
status = 1;
break;
}
}
if (status)
break;
}
if (status)
break;
}

puts ("Escaped from loop.");

/* End */

You forgot

int ok = 1;

while (ok && test[0])
while (ok && test[1])
while (ok && test[2])
{
if (test[3])
ok = 0;
}
puts ("Escaped from loop.");

--
Ian Collins.
Jun 23 '06 #5

P: n/a
mi********@gmail.com wrote:
you can write any code that uses a goto, without a goto.

Goto is disliked, as it leads to code that is harder to read. You
should try to eliminate goto's as it will make somebody(other then you)
able to edit your code.


Common newbieism. Try code like

----
if (func1() != OK) { goto ERR; }
stmt1;
if (func2() != OK) { goto ERR; }
stmt2;
if (func3() != OK) { goto ERR; }
stmt3;

return OK;
ERR:
/* err occured, deal with it */
---

versus the "smart" way

---
if (func1() != OK) { deal_with_error; }
stmt1;
if (func2() != OK) { deal_with_error; }
stmt2;
if (func3() != OK) { deal_with_error; }
stmt3;
----

Where deal_with_error could be say 10-25 lines of cleanup code
depending on the function. Now pretend you're writing a function that
has 40 blocks like that [say doing a lot of failable bignum math
calls].

goto is no more evil than the "do" keyword. I could just as easily
write incomprehensible switch statements too...

switch (mychar == 'Y') {
case 0: do_something();
default: or_not();
}

etc, etc, etc.

Anyone who claims "goto" is evil basically hasn't written a
sufficiently complicated enough program yet.

Tom

Jun 23 '06 #6

P: n/a
mi********@gmail.com top-posted:
you can write any code that uses a goto, without a goto.

Goto is disliked, as it leads to code that is harder to read. You
should try to eliminate goto's as it will make somebody(other then you)
able to edit your code.
jaso wrote:
Can you give any comments on this code?
I used one goto, is it bad? <snip>
/* Fills record with input from user */
int fill_record(struct record r)
{
size_t i;
for (i = 0; i < r.count; i++) {

field_prompt(r.desc[i]);
if (get_field(&r.entries[i], r.desc[i]) == EOF)
goto atEOF;

while (validate_entry(r.entries[i], r.desc[i]) != 0) {
free(r.entries[i]);
field_prompt(r.desc[i]);
if (get_field(&r.entries[i], r.desc[i]) == EOF)
goto atEOF;
}
}

return 0;

atEOF:
while (i--) {
free(r.entries[i]);
r.entries[i] = NULL;
}
return EOF;
}


This is a perfectly acceptable use of goto, and IMO is the
correct way to code this. The label is at the end of the block
and is used to bail out of the inner loop and do clean-up.
There's nothing wrong with that, and there's no point in
bending over backwards to write convoluted error handling
just because someone once wrote that goto is bad.

Jun 23 '06 #7

P: n/a
"mi********@gmail.com" <mi********@gmail.com> wrote:
you can write any code that uses a goto, without a goto.

Goto is disliked, as it leads to code that is harder to read. You
should try to eliminate goto's as it will make somebody(other then you)
able to edit your code.


Absolutism is bad for your soul, especially when it's top-posted and
wrongly applied, like yours.

Richard
Jun 23 '06 #8

P: n/a
mi********@gmail.com wrote:
you can write any code that uses a goto, without a goto.

duffs device.
Goto is disliked, as it leads to code that is harder to read. You
should try to eliminate goto's as it will make somebody(other then you)
able to edit your code.


Yup, goto and longjmp/setjmp make code so hard to read
that they're considered harmful!

/sarcasm

Readability and unconditional jumps are not necessarily
mutually exclusive, you know.

goose

<snipped>

Jun 23 '06 #9

P: n/a

jaso wrote:
Can you give any comments on this code?
I used one goto, is it bad?


Sometimes there's a way to rearrange the logic
to eliminate the goto. This will usually make
the code slightly more maintainable but, in your
example, would hardly be worth the bother.

Let me follow up on my own 'goto' query
from almost a year ago. The present comp.lang.c
players seem intelligent and open-minded.
I hope they'll humor me and "vote" on my case.

Tim Rentsch submitted only a "pseudo-code" synopsis
(Usenet msg <kf*************@alumnus.caltech.edu>),
but that's just as well: I've abbreviated my
own code the same way; lengthy but irrelevant
details are removed and an easy comparison can
be made.

I've never denied that goto's are *bad*.
The point is that other things (longjmp(),
redundant tests, break, inside-loop state changes,
etc.) are also bad to varying degrees and one
seeks compromise. In the particular code below,
the 'goto' may seem *horrendously* unstructured
but study reveals a strict and elegant structure,
albeit a highly non-standard one.

* * * * * * * * * * * * *

I'll show the actual pseudocode routines in
a moment, but I found a simple way to abbreviate
them further and highlight the different flow
construction. The details of Tim's routine are
identical to mine except for the associated flow
and looping controls. By deleting all *identical*
lines, we see exactly what changes Tim required
to eliminate the 'goto':

Version 1 (omitting parts identical to Version 2):
ITERATE through tricks until outcome is decided
ITERATE clockwise through players
try_again:
ITERATE through tricks backwards until done
ITERATE counterclockwise through players
If Need to Backtrack
GOTO try_again;

Version 2 (omitting parts identical to Version 2):
ITERATE FOREVER
ITERATE FOREVER
If trick complete
ADVANCE STATE to next trick;
If outcome decided
BREAK;
Else ADVANCE to next player;
ITERATE FOREVER
If trick empty
If done
return or exit;
REGRESS STATE to previous trick;
Else REGRESS to previous player;
If Need to Backtrack
BREAK;
My "Iterates" are simple for-loops to iterate through
the 13 tricks of a whist hand, or the four cards played
to a trick. Tim couldn't use these (he'd need 'goto'
or C's non-existent 'break 2') so resorted to inside-loop
state changes. For me, replacing the clear and elegant
'for (;;iteration)' construct with a forever-loop and
inside-loop state changes is highly undesirable.
Anyway, forever-loops are always at least *slightly*
bad: "nothing is forever" but the ending
condition is hidden inside the loop with an
If ... Break or If ... Return.

Please compare the two fragments and decide which is
"better." On balance, one might say that the first
fragment is similar to the second but replaces 2 breaks,
4 state changes and an inside-loop return(*) with just
one for-loop and one goto. (* -- I don't think a return
or exit() inside a loop is that big of a problem, but
it is objectionable and the fact that the first fragment
naturally finishes at its end does seem nice.)

* * * * * * * * * * * * *

Version 1:
Initialize;
ITERATE through tricks until outcome is decided {
Set trick to empty;
ITERATE clockwise through players {
Determine available legal plays;
try_again:
Choose a legal card, and play it to trick;
}
Determine trick's winner, adjusting score;
}
ITERATE through tricks backwards until done {
ITERATE counterclockwise through players {
Retract played card;
Delete it from available plays;
If (card led to defeat)
&& (alternatives remain) {
GOTO try_again;
}
}
}
Print solution and exit;
Version 2:
Initialize;
ITERATE FOREVER {
ITERATE FOREVER {
Determine available legal plays;
Choose a legal card, and play it to trick;
If trick complete {
Determine trick's winner, adjusting score;
If outcome decided {
BREAK;
}
ADVANCE STATE to next trick;
Set trick to empty;
} Else ADVANCE to next player;
}
ITERATE FOREVER {
If trick empty {
If done {
Print solution and exit;
}
REGRESS STATE to previous trick;
} Else REGRESS to previous player;
Retract played card;
Delete it from available plays;
If (card led to defeat)
&& (alternatives remain) {
BREAK;
}
}
}
Which code is more readable?

* * * * * * * * * * * * *

BTW, peoply rightly complain that the problem
with 'goto' is the need to grok all references
to the associated label but, in any non-trivial
case, isn't an editor search for all occurrences
of that label the first thing you do? No one's
trying to defend spaghetti code with a maze of
goto's.

During the Jurassic Era many of us didn't have
editors but assemblers printed an index of
references. I was always baffled when someone
overlooked an identifier's purpose: when making
a change I always checked the reference index
when I had any uncertainty about an identifier.

* * * * * * * * * * * * *

History of this "Code Fragment":

The "code fragment" is actually a complete program to
solve a non-trivial problem (double-dummy whist analysis),
but I call it "fragment" because I've used "pseudo-code"
to reduce it to a few lines.

Version 1 (compilable C, not this pseudocode) and some
further comments are on display at
http://tinyurl.com/2452h/dbldum.htm

James Dow Allen

- - - - - - - - - - -
Tell us, Senator, what is your opinion of alcohol?

``Well, if by alcohol you mean that hearty spirit which brings laughter
and
livelihood to social gatherings, which lubricates the gears of
business
transactions, which makes life's hardships easier to bear, then I say
hurrah for it, and I support its legal sale and consumption.

``However, if by alcohol you mean that evil essence which robs the
family
budget, which is a toxin to the body and the mind, which causes men
to
assault one another and to fail in their professions, then I say fie
on
it, and I will work with all my power to prevent its sale and
consumption.''

- - - - - - - - - - -

Jun 24 '06 #10

P: n/a
Tom St Denis wrote:
mi********@gmail.com wrote:
you can write any code that uses a goto, without a goto.

Goto is disliked, as it leads to code that is harder to read. You
should try to eliminate goto's as it will make somebody(other then you)
able to edit your code.


Common newbieism. Try code like

----
if (func1() != OK) { goto ERR; }
stmt1;
if (func2() != OK) { goto ERR; }
stmt2;
if (func3() != OK) { goto ERR; }
stmt3;

return OK;
ERR:
/* err occured, deal with it */
---

versus the "smart" way

---
if (func1() != OK) { deal_with_error; }
stmt1;
if (func2() != OK) { deal_with_error; }
stmt2;
if (func3() != OK) { deal_with_error; }
stmt3;
----

Where deal_with_error could be say 10-25 lines of cleanup code
depending on the function. Now pretend you're writing a function that
has 40 blocks like that [say doing a lot of failable bignum math
calls].

goto is no more evil than the "do" keyword. I could just as easily
write incomprehensible switch statements too...

switch (mychar == 'Y') {
case 0: do_something();
default: or_not();
}

etc, etc, etc.

Anyone who claims "goto" is evil basically hasn't written a
sufficiently complicated enough program yet.

Tom

I don't claim goto evil except that it destroys program structure. I
have only ever used goto in little test programs to see how it works. I
am much more a fan of break and continue to defeat looping blocks.

--
Joe Wright
"Everything should be made as simple as possible, but not simpler."
--- Albert Einstein ---
Jun 25 '06 #11

P: n/a
Programs written with the goto, loose structure, and according to
Dijkstra you can write anything without the goto. The problem is not
with simple cases, but with the more complicated cases.

BTW, requiring top posting is more absolutist than elmimiating goto's.

Richard Bos wrote:
"mi********@gmail.com" <mi********@gmail.com> wrote:
you can write any code that uses a goto, without a goto.

Goto is disliked, as it leads to code that is harder to read. You
should try to eliminate goto's as it will make somebody(other then you)
able to edit your code.


Absolutism is bad for your soul, especially when it's top-posted and
wrongly applied, like yours.

Richard


Jul 1 '06 #12

P: n/a

Andrew Poelstra wrote:
On 2006-06-23, mi********@gmail.com <mi********@gmail.com> wrote:
you can write any code that uses a goto, without a goto.

Goto is disliked, as it leads to code that is harder to read. You
should try to eliminate goto's as it will make somebody(other then you)
able to edit your code.


Don't top-post. I've eliminated what you quoted because it isn't really
relevant to your point.

What is easier to read:
/* Start */

while (test[0])
while (test[1])
while (test[2])
{
if (test[3])
goto outOfLoop;
}

outOfLoop:
puts ("Escaped from loop.");
/* End */

Or, without goto:

/* Start */

int status = 0;

while (test[0])
{
while (test[1])
{
while (test[2])
{
if (test[3])
{
status = 1;
break;
}
}
if (status)
break;
}
if (status)
break;
}

puts ("Escaped from loop.");

/* End */

--
Andrew Poelstra < http://www.wpsoftware.net/blog >
To email me, use "apoelstra" at the above address.
I know that area of town like the back of my head.


while(test[0] || test[1] || test[2])
{
if(test[3])
break;
}

Jul 1 '06 #13

P: n/a
Andrew Poelstra said:

<snip>
What is easier to read:
/* Start */

while (test[0])
while (test[1])
while (test[2])
{
if (test[3])
goto outOfLoop;
}

outOfLoop:
puts ("Escaped from loop.");
Now add sixty to a hundred lines of actual code, ten lines of comments, and
a couple of years of maintenance, and /then/ ask me whether this is easy to
read.
Or, without goto:


Unstructured version snipped. The break keyword is just goto in a false
moustache.

In practice, status objects are cheap and readable. If they are becoming
unreadable, it's a sign that your function is too big. One huge advantage
of a modular design with strict avoidance of goto, non-documentary
continue, and switchless break, is that it is really easy to refactor a
function that has outgrown its readability. Just chop out the innermost
loop, dump it into a new function, and that's typically almost all that you
have to do. When the control flow is hopping all over the place like a frog
on his wedding night, code simplification is far more difficult to achieve.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Jul 1 '06 #14

P: n/a
On 2006-07-01, mi********@gmail.com <mi********@gmail.com> wrote:

Andrew Poelstra wrote:
On 2006-06-23, mi********@gmail.com <mi********@gmail.com> wrote:
> you can write any code that uses a goto, without a goto.
>
> Goto is disliked, as it leads to code that is harder to read. You
> should try to eliminate goto's as it will make somebody(other then you)
> able to edit your code.
>


Don't top-post. I've eliminated what you quoted because it isn't really
relevant to your point.

What is easier to read:
/* Start */

while (test[0])
while (test[1])
while (test[2])
{
if (test[3])
goto outOfLoop;
}

outOfLoop:
puts ("Escaped from loop.");
/* End */

Or, without goto:

/* Start */

int status = 0;

while (test[0])
{
while (test[1])
{
while (test[2])
{
if (test[3])
{
status = 1;
break;
}
}
if (status)
break;
}
if (status)
break;
}

puts ("Escaped from loop.");

/* End */

--
Andrew Poelstra < http://www.wpsoftware.net/blog >
To email me, use "apoelstra" at the above address.
I know that area of town like the back of my head.


while(test[0] || test[1] || test[2])
{
if(test[3])
break;
}


Did I need to clarify that there was other code in there?
Convert this to one while loop:
while (test[0]) {
puts ("Test[0]");
while (test[1]) {
puts ("Test[1]");
while (test[2]) {
puts ("Test[2]");
if (test[3])
goto goatee;
}
}
}

goatee:
puts ("Test[3] or !Test[0]");

(That's also a reason for why I don't use that bracing style.)

There were other, much better ways, posted for me getting around
using a goto in that situation.

--
Andrew Poelstra <http://www.wpsoftware.net/blog>
To email me, use "apoelstra" at the above address.
"You people hate mathematics." -- James Harris
Jul 1 '06 #15

P: n/a
On 2006-07-01, Richard Heathfield <in*****@invalid.invalid> wrote:
Andrew Poelstra said:

<snip>
What is easier to read:
/* Start */

while (test[0])
while (test[1])
while (test[2])
{
if (test[3])
goto outOfLoop;
}

outOfLoop:
puts ("Escaped from loop.");


Now add sixty to a hundred lines of actual code, ten lines of comments, and
a couple of years of maintenance, and /then/ ask me whether this is easy to
read.
Or, without goto:


Unstructured version snipped. The break keyword is just goto in a false
moustache.

In practice, status objects are cheap and readable. If they are becoming
unreadable, it's a sign that your function is too big. One huge advantage
of a modular design with strict avoidance of goto, non-documentary
continue, and switchless break, is that it is really easy to refactor a
function that has outgrown its readability. Just chop out the innermost
loop, dump it into a new function, and that's typically almost all that you
have to do. When the control flow is hopping all over the place like a frog
on his wedding night, code simplification is far more difficult to achieve.


Since as a maintenance programmer you've probably had to deal with a lot of
similar code, suppose you were writing a parser and you did this:

c = get_input();

if (we_are_in_a_quote && c != '\"')
goto skip_parsing;

switch (c)
{
/* Parsing code here */
}

skip_parsing:
/* Return parsed text to callee. */
Would that be an appropriate use of goto? Otherwise I've found that I end up
with if statements around most every single case block. (I can't do it around
the whole switch because I don't care if I'm in quotes when checking for the
quote character and the escape character).

--
Andrew Poelstra <http://www.wpsoftware.net/blog>
To email me, use "apoelstra" at the above address.
"You people hate mathematics." -- James Harris
Jul 1 '06 #16

P: n/a
Andrew Poelstra said:

<snip>

Since as a maintenance programmer you've probably had to deal with a lot
of similar code, suppose you were writing a parser and you did this:

c = get_input();

if (we_are_in_a_quote && c != '\"')
goto skip_parsing;

switch (c)
{
/* Parsing code here */
}

skip_parsing:
/* Return parsed text to callee. */
Would that be an appropriate use of goto?


I wouldn't use goto in that situation, no. I'd use a state machine
architecture, looping while state != DONE, and inside the loop I'd use a
switch statement, one case per state.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Jul 1 '06 #17

P: n/a
Andrew Poelstra wrote:
On 2006-07-01, Richard Heathfield <in*****@invalid.invalid> wrote:

In practice, status objects are cheap and readable. If they are becoming
unreadable, it's a sign that your function is too big. One huge advantage
of a modular design with strict avoidance of goto, non-documentary
continue, and switchless break, is that it is really easy to refactor a
function that has outgrown its readability. Just chop out the innermost
loop, dump it into a new function, and that's typically almost all that you
have to do. When the control flow is hopping all over the place like a frog
on his wedding night, code simplification is far more difficult to achieve.

Since as a maintenance programmer you've probably had to deal with a lot of
similar code, suppose you were writing a parser and you did this:

c = get_input();

if (we_are_in_a_quote && c != '\"')
goto skip_parsing;

switch (c)
{
/* Parsing code here */
}

skip_parsing:
/* Return parsed text to callee. */
Would that be an appropriate use of goto? Otherwise I've found that I end up
with if statements around most every single case block. (I can't do it around
the whole switch because I don't care if I'm in quotes when checking for the
quote character and the escape character).

I agree 100% with Richard's comments, the cleaner the code structure,
the easier it is to refactor. That's why my last team banned goto outright.

In the parser example, I would call a function for each case and include
the test for quotes explicitly where required. I think this makes the
code clearer.

--
Ian Collins.
Jul 1 '06 #18

P: n/a
Ian Collins posted:

> I agree 100% with Richard's comments, the cleaner the code structure,
the easier it is to refactor. That's why my last team banned goto
outright.

I find "goto" necessary when I have nested loops, for example:
while ( expr1 )
{
while ( expr2 )
{
while ( expr3 )
{
goto OUT_OF_ALL_LOOPS;
}
}
}

OUT_OF_ALL_LOOPS: ;
In my own humble opinion, I think it's childish to outright ban something
when it comes to computer programming -- I feel it gives an air of
inconfidence in one's competence.
--

Frederick Gotham
Jul 1 '06 #19

P: n/a
On 2006-07-01, Frederick Gotham <fg*******@SPAM.com> wrote:
> Ian Collins posted:

>> I agree 100% with Richard's comments, the cleaner the code structure,
the easier it is to refactor. That's why my last team banned goto
outright.


I find "goto" necessary when I have nested loops, for example:
while ( expr1 )
{
while ( expr2 )
{
while ( expr3 )
{
goto OUT_OF_ALL_LOOPS;
}
}
}

OUT_OF_ALL_LOOPS: ;
In my own humble opinion, I think it's childish to outright ban something
when it comes to computer programming -- I feel it gives an air of
inconfidence in one's competence.
This can be done in a way that is more clear (in most cases) like so:

while (expr1 && !done)
while (expr2 && !done)
while (expr3 && !done)
if (expr4)
done = 1;

This has already been mentioned in this thread. You might want to find some
archives of it. (Googling comp.lang.c "thread name" will usually get you a
lot of good archives).

--
Andrew Poelstra <http://www.wpsoftware.net/blog>
To email me, use "apoelstra" at the above address.
"You people hate mathematics." -- James Harris
Jul 1 '06 #20

P: n/a
Frederick Gotham said:

<snip>
> In my own humble opinion, I think it's childish to outright ban something
when it comes to computer programming -- I feel it gives an air of
inconfidence in one's competence.
It's not a question of banning goto. If I think a goto can improve the
readability and maintainability of my code, I'm ready to use one tomorrow.
Or even tonight. Right now.

And yet, if you discount explain-how-goto-works code, I haven't used a goto
in all the seventeen years I've been writing in C. That's because, so far,
I haven't come across a circumstance that I felt warranted it - not even
once.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Jul 1 '06 #21

P: n/a
Andrew Poelstra posted:

> This can be done in a way that is more clear (in most cases) like so:

while (expr1 && !done)
while (expr2 && !done)
while (expr3 && !done)
if (expr4)
done = 1;

Yes, that works. Things get more and more complicated though if you want
a double-break, or a tripple_break.

Perhaps it would be handy if the break statement were given extra
functionality:

int main()
{
while (expr1)
{
while(expr2)
{
while(expr3)
{
while(expr4)
{
break(3); /* This is a tripple break */
}
}
}
}

}
--

Frederick Gotham
Jul 1 '06 #22

P: n/a
In article <R4******************************@comcast.com>,
Joe Wright <jo********@comcast.netwrote:
>Tom St Denis wrote:
>mi********@gmail.com wrote:
>>you can write any code that uses a goto, without a goto.

Goto is disliked, as it leads to code that is harder to read. You
should try to eliminate goto's as it will make somebody(other then you)
able to edit your code.

Common newbieism. Try code like

----
if (func1() != OK) { goto ERR; }
stmt1;
if (func2() != OK) { goto ERR; }
stmt2;
if (func3() != OK) { goto ERR; }
stmt3;

return OK;
ERR:
/* err occured, deal with it */
---

versus the "smart" way

---
if (func1() != OK) { deal_with_error; }
stmt1;
if (func2() != OK) { deal_with_error; }
stmt2;
if (func3() != OK) { deal_with_error; }
stmt3;
----

Where deal_with_error could be say 10-25 lines of cleanup code
depending on the function. Now pretend you're writing a function that
has 40 blocks like that [say doing a lot of failable bignum math
calls].

goto is no more evil than the "do" keyword. I could just as easily
write incomprehensible switch statements too...

switch (mychar == 'Y') {
case 0: do_something();
default: or_not();
}

etc, etc, etc.

Anyone who claims "goto" is evil basically hasn't written a
sufficiently complicated enough program yet.

Tom
I don't claim goto evil except that it destroys program structure. I
have only ever used goto in little test programs to see how it works. I
am much more a fan of break and continue to defeat looping blocks.
But there were no looping blocks in the post your were replying to.
Break and continue won't help you there.

--
Rouben Rostamian
Jul 1 '06 #23

P: n/a
Frederick Gotham said:

<snip>
>
Perhaps it would be handy if the break statement were given extra
functionality:
Less would be better. If break /only/ worked in switch cases, and no longer
allowed arbitrary loop termination, I'd be much happier with it.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Jul 1 '06 #24

P: n/a
Frederick Gotham wrote:
Ian Collins posted:
>>I agree 100% with Richard's comments, the cleaner the code structure,
the easier it is to refactor. That's why my last team banned goto
outright.

I find "goto" necessary when I have nested loops, for example:
Apply more imagination.
>
while ( expr1 )
{
while ( expr2 )
{
while ( expr3 )
{
goto OUT_OF_ALL_LOOPS;
}
}
}

OUT_OF_ALL_LOOPS: ;
I posted a viable alternative last week.
>
In my own humble opinion, I think it's childish to outright ban something
when it comes to computer programming -- I feel it gives an air of
inconfidence in one's competence.
Well that's team democracy at work. We preferred well structured code
that was easy to refactor. Try extracting your inner loop to a function.

--
Ian Collins.
Jul 1 '06 #25

P: n/a
mi********@gmail.com wrote:

<top posting fixed>
Richard Bos wrote:
>"mi********@gmail.com" <mi********@gmail.comwrote:
>>you can write any code that uses a goto, without a goto.

Goto is disliked, as it leads to code that is harder to read. You
should try to eliminate goto's as it will make somebody(other then you)
able to edit your code.
Absolutism is bad for your soul, especially when it's top-posted and
wrongly applied, like yours.

Programs written with the goto, loose structure, and according to
Dijkstra you can write anything without the goto. The problem is not
with simple cases, but with the more complicated cases.
Yes, it is hard to write code to solve some complex problems without
using goto in C. Or was that not what you meant?

As someone who dislikes goto, I would say that there are situations
which can be handled nice and simply with a goto where other options
provided by C would be harder for me to read.
BTW, requiring top posting is more absolutist than elmimiating goto's.
You miss-understood Richard. He was complaining about your top-posting,
not requiring that you do it. Please don't top-post in future.
--
Flash Gordon, living in interesting times.
Web site - http://home.flash-gordon.me.uk/
comp.lang.c posting guidelines and intro:
http://clc-wiki.net/wiki/Intro_to_clc
Jul 1 '06 #26

P: n/a
On 2006-07-01, Frederick Gotham <fg*******@SPAM.comwrote:
Andrew Poelstra posted:

>This can be done in a way that is more clear (in most cases) like so:

while (expr1 && !done)
while (expr2 && !done)
while (expr3 && !done)
if (expr4)
done = 1;


Yes, that works. Things get more and more complicated though if you want
a double-break, or a tripple_break.

Perhaps it would be handy if the break statement were given extra
functionality:

int main()
{
while (expr1)
while(expr2)
while(expr3)
while(expr4)
break(3); /* This is a tripple break */
}
That's content-less example code and had to read it thrice to understand it.
Then I had to count the while statements backwards...

I agree 100% with Richard Healthfield here; less break usage is better.

--
Andrew Poelstra <http://www.wpsoftware.net/blog>
To email me, use "apoelstra" at the above address.
"You people hate mathematics." -- James Harris
Jul 1 '06 #27

P: n/a
Frederick Gotham <fg*******@SPAM.comwrites:
Andrew Poelstra posted:
>This can be done in a way that is more clear (in most cases) like so:

while (expr1 && !done)
while (expr2 && !done)
while (expr3 && !done)
if (expr4)
done = 1;

Yes, that works. Things get more and more complicated though if you want
a double-break, or a tripple_break.

Perhaps it would be handy if the break statement were given extra
functionality:

int main()
{
while (expr1)
{
while(expr2)
{
while(expr3)
{
while(expr4)
{
break(3); /* This is a tripple break */
}
}
}
}

}
I've been advocating a multi-level break construct for a long time,
but this is *not* the way to do it. 3 is a magic number here; if I
change the code later, I have to go back and count the levels all over
again, and I'm very likely to get it wrong.

If a multi-level break were added to the language, it should specify
the *name* of the loop. The simplest way to do this would be to add a
new use for goto labels:

int main()
{
FOO:
while (expr1)
{
BAR:
while(expr2)
{
BAZ:
while(expr3)
{
QUUX:
while(expr4)
{
break BAR;
}
}
}
}
}

What I'd really like to do (i.e., what I'd do if I were inventing the
language from scratch) is provide something other than a goto label,
something that, rather than naming a specific point in the code,
provides a name for an entire loop statement. The "break BAR;"
wouldn't mean "jump to location BAR"; it would mean "break out of the
loop or switch statement whose name is BAR".

Ignoring backward compatibility, I'd probably use the "identifier:"
syntax for loop names, and invent a different syntax (one that stands
out more) for goto labels. <OT>This is what Ada does; loop names are
of the form "identifier:", and goto labels are of the form
"<<identifier>>".</OT>

But since we don't have the opportunity to re-invent the language from
scratch, I could live with re-using goto labels, unless someone can
come up with a more reasonable syntax.

(I know, let's re-use "static"!)

Richard has argued that the existing "break" for loops is itself a bad
idea. If so, a multi-level break is a worse idea, but I respectfully
disagree with Richard's premise.

(A note to certain trolls: observe that it's possible to disagree with
someone without being insulting.)

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Jul 2 '06 #28

P: n/a
Keith Thompson (in ln************@nuthaus.mib.org) said:

| I've been advocating a multi-level break construct for a long time,
| but this is *not* the way to do it. 3 is a magic number here; if I
| change the code later, I have to go back and count the levels all
| over again, and I'm very likely to get it wrong.
|
| If a multi-level break were added to the language, it should specify
| the *name* of the loop. The simplest way to do this would be to
| add a new use for goto labels:

I dunno... I think I'd like something more directed like 'breakto' to
avoid having to screw around with counting (curly) braces, etc.

Aha! How about:

#define breakto goto

? :-)

--
Morris Dovey
DeSoto Solar
DeSoto, Iowa USA
http://www.iedu.com/DeSoto
Jul 2 '06 #29

P: n/a
Keith Thompson said:

<snip>
>
Richard has argued that the existing "break" for loops is itself a bad
idea.
Yes.
If so, a multi-level break is a worse idea,
Yes!
but I respectfully disagree with Richard's premise.
Fine by me, but may I ask why?

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Jul 2 '06 #30

P: n/a
Richard Heathfield <in*****@invalid.invalidwrites:
Keith Thompson said:

<snip>
>>
Richard has argued that the existing "break" for loops is itself a bad
idea.

Yes.
>If so, a multi-level break is a worse idea,

Yes!
>but I respectfully disagree with Richard's premise.

Fine by me, but may I ask why?
Because I find "break" to be useful. IMHO, it's a good and clear way
to break out of a loop when that's what I want to do.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Jul 2 '06 #31

P: n/a
Keith Thompson wrote:
>
I've been advocating a multi-level break construct for a long time,
but this is *not* the way to do it. 3 is a magic number here; if I
change the code later, I have to go back and count the levels all over
again, and I'm very likely to get it wrong.

If a multi-level break were added to the language, it should specify
the *name* of the loop. The simplest way to do this would be to add a
new use for goto labels:

int main()
{
FOO:
while (expr1)
{
BAR:
while(expr2)
{
BAZ:
while(expr3)
{
QUUX:
while(expr4)
{
break BAR;
}
}
}
}
}
What happens if you refactor out the inner loop?

Using break is almost a bad as goto at disrupting code structure. If
you want to exit a loop when a condition occurs, why not just test for it?

--
Ian Collins.
Jul 2 '06 #32

P: n/a
Andrew Poelstra wrote:
On 2006-07-01, Frederick Gotham <fg*******@SPAM.comwrote:
Ian Collins posted:

I agree 100% with Richard's comments, the cleaner the code structure,
the easier it is to refactor. That's why my last team banned goto
outright.

I find "goto" necessary when I have nested loops, for example:
while ( expr1 )
{
while ( expr2 )
{
while ( expr3 )
{
goto OUT_OF_ALL_LOOPS;
}
}
}

OUT_OF_ALL_LOOPS: ;
In my own humble opinion, I think it's childish to outright ban something
when it comes to computer programming -- I feel it gives an air of
inconfidence in one's competence.

This can be done in a way that is more clear (in most cases) like so:

while (expr1 && !done)
while (expr2 && !done)
while (expr3 && !done)
if (expr4)
done = 1;
IME, nothing is ever quite so simple ...

A use of gotos (well, setjmp/longjmp actually) is sort of like
setting an exception:

int foo_new (jmp_buf e)
{
...
if (malloc_failed) longjmp (e, FOO_NO_MEM);
...
if (file_unopenable) longjmp (E, FOO_FILE_FAILED);
...
}

Add a few more functions to the foo module, each of'
which uses longjmp to represent failure then you'll
get usage like this:

jmp_buf saved;
int result = setjmp (saved);
if (result) {
switch (result) {
case FOO_NO_MEM: /* ran out of memory */
case FOO_FILE_FAILED: /* file access failure */
case FOO_MAX_OBJECTS: /* maximum objects created */
/* Put all your other module failures here */
}
}

/* And now this is the code that would have had a goto or the
* loops from your post above.
*/
handle = foo_new (saved);
foo_dothis (saved, handle);
foo_dothat (saved, handle);
foo_dotheotherthing (saved, handle);
foo_del (saved, handle);
See? Try and write that away with loops :-)
This does mean, of course, that you'll need to do it
for every module, which can quickly get out of hand.

On the bright side, your error handling code is
read *before* any code actually executes, which
clues the maintainer (ME!!!) into what you *think*
should be the valid errors only; Add a default to
the error-handling switch and you can even print
diagnostics for the ones you *don't* expect.

I'm mostly a maintainer for other (sometimes clueless)
coders; I maintain code that even the original coders
sometimes have problems with.

I *always* think of the maintainer first, mainly because
I'm selfish and would like to make my job easier :-)

goose,
Goto: goto Goto;

Jul 3 '06 #33

P: n/a
Ian Collins wrote:
Frederick Gotham wrote:
<snipped>

In my own humble opinion, I think it's childish to outright ban something
when it comes to computer programming -- I feel it gives an air of
inconfidence in one's competence.
Well that's team democracy at work. We preferred well structured code
that was easy to refactor. Try extracting your inner loop to a function.
Do you program in a language other than C? Do you use exceptions
in those languages? Exceptions are just another form of gotos,
only its "goto that location and tell the code there that this
happened" and not just "goto the error location, it will
unconditionally execute code to handle errors". No one ever seemed
to have trouble refactoring code which generated excetpions.

Ban away all you want; exceptions got popular *because*
developers wanted a structured way to handle errors. Handling
errors is not part of the algorithm logic; I see a benefit in
moving the code that checks for and handles specific errors
outside the block that contains the logic. Others see this benefit
as well, hence the popularity of exceptions.

Did you ban setjmp/longjmp too?

goose,
not being rhetorical - I'd really like to know.

Jul 3 '06 #34

P: n/a
Andrew Poelstra wrote:
On 2006-07-01, Frederick Gotham <fg*******@SPAM.comwrote:
Ian Collins posted:

I agree 100% with Richard's comments, the cleaner the code structure,
the easier it is to refactor. That's why my last team banned goto
outright.

I find "goto" necessary when I have nested loops, for example:
while ( expr1 )
{
while ( expr2 )
{
while ( expr3 )
{
goto OUT_OF_ALL_LOOPS;
}
}
}

OUT_OF_ALL_LOOPS: ;
In my own humble opinion, I think it's childish to outright ban something
when it comes to computer programming -- I feel it gives an air of
inconfidence in one's competence.

This can be done in a way that is more clear (in most cases) like so:

while (expr1 && !done)
while (expr2 && !done)
while (expr3 && !done)
if (expr4)
done = 1;
IME, nothing is ever quite so simple ...

A use of gotos (well, setjmp/longjmp actually) is sort of like
setting an exception:

int foo_new (jmp_buf e)
{
...
if (malloc_failed) longjmp (e, FOO_NO_MEM);
...
if (file_unopenable) longjmp (E, FOO_FILE_FAILED);
...
}

Add a few more functions to the foo module, each of'
which uses longjmp to represent failure then you'll
get usage like this:

jmp_buf saved;
int result = setjmp (saved);
if (result) {
switch (result) {
case FOO_NO_MEM: /* ran out of memory */
case FOO_FILE_FAILED: /* file access failure */
case FOO_MAX_OBJECTS: /* maximum objects created */
/* Put all your other module failures here */
}
}

/* And now this is the code that would have had a goto or the
* loops from your post above.
*/
handle = foo_new (saved);
foo_dothis (saved, handle);
foo_dothat (saved, handle);
foo_dotheotherthing (saved, handle);
foo_del (saved, handle);
See? Try and write that away with loops :-)
This does mean, of course, that you'll need to do it
for every module, which can quickly get out of hand.

On the bright side, your error handling code is
read *before* any code actually executes, which
clues the maintainer (ME!!!) into what you *think*
should be the valid errors only; Add a default to
the error-handling switch and you can even print
diagnostics for the ones you *don't* expect.

I'm mostly a maintainer for other (sometimes clueless)
coders; I maintain code that even the original coders
sometimes have problems with.

I *always* think of the maintainer first, mainly because
I'm selfish and would like to make my job easier :-)

goose,
Goto: goto Goto;

Jul 3 '06 #35

P: n/a
Keith Thompson said:
Richard Heathfield <in*****@invalid.invalidwrites:
>Keith Thompson said:

<snip>
>>>
Richard has argued that the existing "break" for loops is itself a bad
idea.

Yes.
>>If so, a multi-level break is a worse idea,

Yes!
>>but I respectfully disagree with Richard's premise.

Fine by me, but may I ask why?

Because I find "break" to be useful. IMHO, it's a good and clear way
to break out of a loop when that's what I want to do.
Yes, syntactically of course it's clear. The issue I have with it is to do
with semantic clarity, not syntactic clarity. In simple cases, there is
usually no difficulty understanding why a break is in place. But as the
codebase grows larger, as the comment density drops, as the all-important
deadlinedeadlineDEADLINE approaches, as the level of hacking around goes up
and the quality of the code goes down, the semantics of control structures
can start to get blurred and fuzzy. I've seen it happen, and I'm sure you
have too. (And there is never any budget for fixing it.) A more rigid
control structure syntax would force the programmer to think about what
he's doing. At present, there are far too many "light-bulb" moments, where
the programmer realises he can achieve his immediate objective with a very
small change. "Aha! I can frob the widgets at precisely the right time if I
just add in: if(v < repackagewidgets(G_KEYVAL, 38, "%%&!-3")) break; that
is a way-cool hack, saved me an hour" - and because it's "only a one-line
change" it "doesn't need commenting".

On the whole, C is still written by hackers, and it shows.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Jul 3 '06 #36

P: n/a
Richard Heathfield wrote:
>
On the whole, C is still written by hackers, and it shows.
Sounds like you've been reading Linux code :)

--
Ian Collins.
Jul 3 '06 #37

P: n/a
goose wrote:
Ian Collins wrote:
>>Frederick Gotham wrote:


<snipped>
>>>In my own humble opinion, I think it's childish to outright ban something
when it comes to computer programming -- I feel it gives an air of
inconfidence in one's competence.

Well that's team democracy at work. We preferred well structured code
that was easy to refactor. Try extracting your inner loop to a function.
Do you program in a language other than C? Do you use exceptions
in those languages? Exceptions are just another form of gotos,
only its "goto that location and tell the code there that this
happened" and not just "goto the error location, it will
unconditionally execute code to handle errors". No one ever seemed
to have trouble refactoring code which generated excetpions.
I do, several. As you say in the next paragraph, exceptions provide a
structured way of passing control. They are /not/ another form of goto,
they do a lot more than simply jumping to another location. There are
plenty of techniques for writing exception safe code. I can't think of
any for writing goto safe code!

If exceptions simply did a longjump, people wouldn't use them.
Ban away all you want; exceptions got popular *because*
developers wanted a structured way to handle errors. Handling
errors is not part of the algorithm logic; I see a benefit in
moving the code that checks for and handles specific errors
outside the block that contains the logic. Others see this benefit
as well, hence the popularity of exceptions.
I'm one of them.

Don't confuse exceptions with gotos, the mechanisms are completely
different. A goto jumps to fixed location, if there are locks held, or
memory to be freed, tough. Exceptions unwind the callstack, allowing
objects created on the stack to be destroyed and any resources they have
claimed to be freed.
Did you ban setjmp/longjmp too?
Yes. Remember this wasn't me, it was my team. I didn't tell them not
to use goto, they decided.
goose,
not being rhetorical - I'd really like to know.

--
Ian Collins.
Jul 3 '06 #38

P: n/a

Ian Collins wrote:
goose wrote:
Ian Collins wrote:
>Frederick Gotham wrote:

<snipped>
>>In my own humble opinion, I think it's childish to outright ban something
when it comes to computer programming -- I feel it gives an air of
inconfidence in one's competence.
Well that's team democracy at work. We preferred well structured code
that was easy to refactor. Try extracting your inner loop to a function.
Do you program in a language other than C? Do you use exceptions
in those languages? Exceptions are just another form of gotos,
only its "goto that location and tell the code there that this
happened" and not just "goto the error location, it will
unconditionally execute code to handle errors". No one ever seemed
to have trouble refactoring code which generated excetpions.
I do, several. As you say in the next paragraph, exceptions provide a
structured way of passing control. They are /not/ another form of goto,
they do a lot more than simply jumping to another location. There are
Well, the issue going back and forth here is not "spurious usage
of gotos" is it? All the examples posted here were reasoned
and informed uses of gotos to *specifically* handle errors. I'd
hardly call the usage of gotos as we've seen here in this thread
/unstructured/. All were written to simulate exceptions in a language
which doesn't have built in support for exceptions.

Exceptions are a structured method for reporting errors; can you
disagree with that statement?
Using gotos to simulate exceptions would be as close as one
can get to exceptions in C.
plenty of techniques for writing exception safe code. I can't think of
any for writing goto safe code!

If exceptions simply did a longjump, people wouldn't use them.
Fair enough; longjmp cannot call destructors automatically like
C++/Java/etc exceptions can but it *can* unwind the stack.
The jmp_buf initialised with setjmp only gets invalidated when the
function scope where setjmp is called returns[1]. I'd assume that,
with language support for destructors (variables going out of
scope automatically get a certain function called), exceptions
can be implemented with longjmp.

<snipped>
Don't confuse exceptions with gotos, the mechanisms are completely
different. A goto jumps to fixed location, if there are locks held, or
memory to be freed, tough.
How is this different from exceptions? I might be way off here, but I
always
assumed that exceptions could only unwind the stack, not magically
unlock or call free (or delete).

Anything allocated on the stack will get freed when longjmp gets
called, too.
Exceptions unwind the callstack, allowing
objects created on the stack to be destroyed and any resources they have
claimed to be freed.
The language (C) does not have support for allowing objects to
specify how they may be safely disposed off; I can envision one or
two ways that longjmp can be used to implement exceptions if the
language did indeed support destructors.

The only difference that I see between exceptions and longjmp is
that exceptions rely on a language feature not found in C.
>
Did you ban setjmp/longjmp too?
Yes. Remember this wasn't me, it was my team. I didn't tell them not
to use goto, they decided.
Sorry, I meant the plural "you" as in "You all".
[1]Well, in a conforming implementation. My current target
has a wierd paging/banking scheme that reuses addresses
so some functions have to load the registers with specific
values to switch banks, else the stack pointer might be
pointing to the stack of the main page. Needless to say,
set/longjmp won't work here and neither will exceptions
(C++ is supported) as they unwind stack but the jmp_buf
(and equivalent in an exception) although holding the value
it was initially set to, will be holding a value thats not valid
in the current context. For pretty much the same reason,
constructors and destructors don't always work the way
one would expect either.
Not that I care much other than in a vaguely academic
way; I write C for these targets :-)

goose,

Jul 3 '06 #39

P: n/a
goose wrote:
Ian Collins wrote:
>>goose wrote:
>>>
Do you program in a language other than C? Do you use exceptions
in those languages? Exceptions are just another form of gotos,
only its "goto that location and tell the code there that this
happened" and not just "goto the error location, it will
unconditionally execute code to handle errors". No one ever seemed
to have trouble refactoring code which generated excetpions.

I do, several. As you say in the next paragraph, exceptions provide a
structured way of passing control. They are /not/ another form of goto,
they do a lot more than simply jumping to another location. There are


Well, the issue going back and forth here is not "spurious usage
of gotos" is it? All the examples posted here were reasoned
and informed uses of gotos to *specifically* handle errors. I'd
hardly call the usage of gotos as we've seen here in this thread
/unstructured/. All were written to simulate exceptions in a language
which doesn't have built in support for exceptions.
In the context they were presented, you could get a way with a goto.
Things beak down when inner loops are extracted into functions.
Exceptions are a structured method for reporting errors; can you
disagree with that statement?
I haven't, if you read what I posted, you'll see I agreed.
Using gotos to simulate exceptions would be as close as one
can get to exceptions in C.
Within a fixed scope, but you still identify the error handler (the
label) at the point of error, where throwing an exception does not.

I think you countered your own argument when you suggested exceptions
can be implemented with longjump, which is closer than goto.
>
>>plenty of techniques for writing exception safe code. I can't think of
any for writing goto safe code!

If exceptions simply did a longjump, people wouldn't use them.


Fair enough; longjmp cannot call destructors automatically like
C++/Java/etc exceptions can but it *can* unwind the stack.
The jmp_buf initialised with setjmp only gets invalidated when the
function scope where setjmp is called returns[1]. I'd assume that,
with language support for destructors (variables going out of
scope automatically get a certain function called), exceptions
can be implemented with longjmp.
True, but we were talking about goto.

--
Ian Collins.
Jul 3 '06 #40

P: n/a
In article <R4******************************@comcast.com>, Joe Wright
<jo********@comcast.netwrote:
Tom St Denis wrote:
mi********@gmail.com wrote:
you can write any code that uses a goto, without a goto.

Goto is disliked, as it leads to code that is harder to read. You
should try to eliminate goto's as it will make somebody(other then you)
able to edit your code.
Common newbieism. Try code like

----
if (func1() != OK) { goto ERR; }
stmt1;
if (func2() != OK) { goto ERR; }
stmt2;
if (func3() != OK) { goto ERR; }
stmt3;

return OK;
ERR:
/* err occured, deal with it */
---

versus the "smart" way

---
if (func1() != OK) { deal_with_error; }
stmt1;
if (func2() != OK) { deal_with_error; }
stmt2;
if (func3() != OK) { deal_with_error; }
stmt3;
----

Where deal_with_error could be say 10-25 lines of cleanup code
depending on the function. Now pretend you're writing a function that
has 40 blocks like that [say doing a lot of failable bignum math
calls].

goto is no more evil than the "do" keyword. I could just as easily
write incomprehensible switch statements too...

switch (mychar == 'Y') {
case 0: do_something();
default: or_not();
}

etc, etc, etc.

Anyone who claims "goto" is evil basically hasn't written a
sufficiently complicated enough program yet.

Tom
I don't claim goto evil except that it destroys program structure. I
have only ever used goto in little test programs to see how it works. I
am much more a fan of break and continue to defeat looping blocks.
I am reminded of an article I read at the height of the "GOTO"
controversy, way back in the 1970's: the author proposed
(tongue-in-cheek) a "COMEFROM" instruction. And he gave an example to
compute the factorial of 3.

The problem with the "COMEFROM" obstruction, of course, is that you had
to scan THE ENTIRE REST OF THE CODEBASE to see if you were supposed to
divert to that instruction. His sample program to compute 3! was the
worst spaghetti I ever saw.

Wikipedia has an interesting article on the concept. As they point
out, breakpoints are actually a form of comefrom.

--
Ron Bruck

Posted Via Usenet.com Premium Usenet Newsgroup Services
----------------------------------------------------------
** SPEED ** RETENTION ** COMPLETION ** ANONYMITY **
----------------------------------------------------------
http://www.usenet.com
Jul 3 '06 #41

P: n/a
Richard Heathfield <in*****@invalid.invalidwrites:
Keith Thompson said:
>Richard Heathfield <in*****@invalid.invalidwrites:
>>Keith Thompson said:

<snip>

Richard has argued that the existing "break" for loops is itself a bad
idea.

Yes.

If so, a multi-level break is a worse idea,

Yes!

but I respectfully disagree with Richard's premise.

Fine by me, but may I ask why?

Because I find "break" to be useful. IMHO, it's a good and clear way
to break out of a loop when that's what I want to do.

Yes, syntactically of course it's clear. The issue I have with it is to do
with semantic clarity, not syntactic clarity. In simple cases, there
is
Semantically it is complicated how? I have never, in real life, seen
anything too complicated involving break that any half competent C
programmer couldnt decipher - especially with commented labels and a
debugged test run.
usually no difficulty understanding why a break is in place. But as the
codebase grows larger, as the comment density drops, as the all-important
deadlinedeadlineDEADLINE approaches, as the level of hacking around goes up
and the quality of the code goes down, the semantics of control structures
can start to get blurred and fuzzy. I've seen it happen, and I'm sure you
have too. (And there is never any budget for fixing it.) A more rigid
A break is no more complicated to debug or check than any complicated C
construct such as a for loop IMO. I have never had an issue with breaks
in code after checking for the obvious newbie/careless errors of fallthrough.

control structure syntax would force the programmer to think about what
he's doing. At present, there are far too many "light-bulb" moments, where
the programmer realises he can achieve his immediate objective with a very
small change. "Aha! I can frob the widgets at precisely the right time if I
just add in: if(v < repackagewidgets(G_KEYVAL, 38, "%%&!-3")) break; that
is a way-cool hack, saved me an hour" - and because it's "only a one-line
change" it "doesn't need commenting".

On the whole, C is still written by hackers, and it shows.
C is a hackers language and many constructs/semantics make it easy to
screw up : from casting to precedence to bracketing to ... etc

break is far from the biggest issue and certainly doesnt deserve
singling out IMO.
--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Jul 3 '06 #42

P: n/a
Ronald Bruck <br***@math.usc.eduwrites:
[...]
I am reminded of an article I read at the height of the "GOTO"
controversy, way back in the 1970's: the author proposed
(tongue-in-cheek) a "COMEFROM" instruction. And he gave an example to
compute the factorial of 3.
INTERCAL actually implements this.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Jul 3 '06 #43

P: n/a
Richard Riley said:

<snip>
>
A break is no more complicated to debug or check than any complicated C
construct such as a for loop IMO. I have never had an issue with breaks
in code after checking for the obvious newbie/careless errors of
fallthrough.
Oh, but I'm not talking about break-out-of-a-case. I'm talking about
break-out-of-a-loop.
<snip>
>>
On the whole, C is still written by hackers, and it shows.

C is a hackers language
In many senses, yes. But the code doesn't /have/ to be unmaintainable.

and many constructs/semantics make it easy to
screw up : from casting to precedence to bracketing to ... etc
Indeed.
break is far from the biggest issue and certainly doesnt deserve
singling out IMO.
I didn't realise I was singling it out. You're right - there's plenty more
wrong with typical C programs than mere control flow issues. But that
doesn't mean control flow issues aren't a problem.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Jul 3 '06 #44

P: n/a
Ian Collins <ia******@hotmail.comwrote:
Keith Thompson wrote:
>>
I've been advocating a multi-level break construct for a long time,
but this is *not* the way to do it. 3 is a magic number here; if I
change the code later, I have to go back and count the levels all over
again, and I'm very likely to get it wrong.

If a multi-level break were added to the language, it should specify
the *name* of the loop. The simplest way to do this would be to add a
new use for goto labels:

int main()
{
FOO:
while (expr1)
{
BAR:
while(expr2)
{
BAZ:
while(expr3)
{
QUUX:
while(expr4)
{
break BAR;
}
}
}
}
}
What happens if you refactor out the inner loop?

Using break is almost a bad as goto at disrupting code structure. If
you want to exit a loop when a condition occurs, why not just test for it?
"just test for it" where? In the condition for the outer loop? How do
you exit a loop in the middle of its body, then? Or halfway through an
inner loop?
Jul 4 '06 #45

P: n/a
On 2006-07-04, Jordan Abel <ra*******@gmail.comwrote:
Ian Collins <ia******@hotmail.comwrote:
>Using break is almost a bad as goto at disrupting code structure. If
you want to exit a loop when a condition occurs, why not just test for it?

"just test for it" where? In the condition for the outer loop? How do
you exit a loop in the middle of its body, then? Or halfway through an
inner loop?
If you're designing your code cleanly, you shouldn't need to jump out of
a loop in the middle. I'm working on an XML parser right now without using
break; to escape from loops. It's a lot trickier to code, but the end result
is actually a fair bit easier to read, maintain, and extend.

That's just my opinion.

--
Andrew Poelstra <http://www.wpsoftware.net/blog>
To email me, use "apoelstra" at the above address.
"You people hate mathematics." -- James Harris
Jul 4 '06 #46

P: n/a
Jordan Abel wrote:
Ian Collins <ia******@hotmail.comwrote:
>>Keith Thompson wrote:
>>>I've been advocating a multi-level break construct for a long time,
but this is *not* the way to do it. 3 is a magic number here; if I
change the code later, I have to go back and count the levels all over
again, and I'm very likely to get it wrong.

If a multi-level break were added to the language, it should specify
the *name* of the loop. The simplest way to do this would be to add a
new use for goto labels:

int main()
{
FOO:
while (expr1)
{
BAR:
while(expr2)
{
BAZ:
while(expr3)
{
QUUX:
while(expr4)
{
break BAR;
}
}
}
}
}

What happens if you refactor out the inner loop?

Using break is almost a bad as goto at disrupting code structure. If
you want to exit a loop when a condition occurs, why not just test for it?


"just test for it" where? In the condition for the outer loop? How do
you exit a loop in the middle of its body, then? Or halfway through an
inner loop?
Where you test the other expressions.

--
Ian Collins.
Jul 4 '06 #47

P: n/a
Ian Collins wrote:
goose wrote:
Ian Collins wrote:
<snipped>
Exceptions are a structured method for reporting errors; can you
disagree with that statement?

I haven't, if you read what I posted, you'll see I agreed.
Just making sure :-)
>
Using gotos to simulate exceptions would be as close as one
can get to exceptions in C.
Within a fixed scope, but you still identify the error handler (the
label) at the point of error, where throwing an exception does not.
Thats right; However I remain to be convinced that this is such
a bad thing. For a function of, say, ten lines (with the error-handling
code) I'd not hesitate to use a goto *when the error handler is
in the same scope*. If exceptions are available, I'd rather throw
an exception but if exceptions are *not* there for me to use
I'd chuck in a goto rather than have the logic code do
unneeded checks.
>
I think you countered your own argument when you suggested exceptions
can be implemented with longjump, which is closer than goto.
Closer to what?
>plenty of techniques for writing exception safe code. I can't think of
any for writing goto safe code!

If exceptions simply did a longjump, people wouldn't use them.

Fair enough; longjmp cannot call destructors automatically like
C++/Java/etc exceptions can but it *can* unwind the stack.
The jmp_buf initialised with setjmp only gets invalidated when the
function scope where setjmp is called returns[1]. I'd assume that,
with language support for destructors (variables going out of
scope automatically get a certain function called), exceptions
can be implemented with longjmp.
True, but we were talking about goto.
Fair enough; I sorta dragged longjmp into this argument because
I consider it to be fairly close in function to a goto. We can
always drop the longjmp argument if you feel that it's a little
more structured.

Back to gotos: I still think that they have a use; sure they
can make code unstructured, but then again just about any
construct can be abused to make code unstructured including
while, for, do and if.

I've never actually *used* goto in any of my code (well, maybe
once :-) but as a maintainer I see "goto error_exit" all the
time in code that is reasonably easy to read.

OTOH, I've had occasion to completely rewrite some "code"
(and I use that term loosely!) because it was so badly written
that it was faster to rewrite than try to figure out how it
worked and what all the status variables meant; yet the code
contained no gotos and only the usual suspects (while, for, etc).

Theres probably a lesson in there somewhere. Perhaps the
"goto error_exit" users are just more likely to have
structured their functions into "init, solve, exit" than
the coders who avoid goto at all costs.

goose,

Jul 4 '06 #48

P: n/a
goose wrote:
Ian Collins wrote:
>>goose wrote:
>>>Ian Collins wrote:

Using gotos to simulate exceptions would be as close as one
can get to exceptions in C.

Within a fixed scope, but you still identify the error handler (the
label) at the point of error, where throwing an exception does not.


Thats right; However I remain to be convinced that this is such
a bad thing. For a function of, say, ten lines (with the error-handling
code) I'd not hesitate to use a goto *when the error handler is
in the same scope*. If exceptions are available, I'd rather throw
an exception but if exceptions are *not* there for me to use
I'd chuck in a goto rather than have the logic code do
unneeded checks.
Well I certainly couldn't justify a goto in a ten line function, then
again I seldom write functions much longer than 10 lines :)
>
>>I think you countered your own argument when you suggested exceptions
can be implemented with longjump, which is closer than goto.


Closer to what?
Exceptions.
>
>>>>plenty of techniques for writing exception safe code. I can't think of
any for writing goto safe code!

If exceptions simply did a longjump, people wouldn't use them.
Fair enough; longjmp cannot call destructors automatically like
C++/Java/etc exceptions can but it *can* unwind the stack.
The jmp_buf initialised with setjmp only gets invalidated when the
function scope where setjmp is called returns[1]. I'd assume that,
with language support for destructors (variables going out of
scope automatically get a certain function called), exceptions
can be implemented with longjmp.

True, but we were talking about goto.
Back to gotos: I still think that they have a use; sure they
can make code unstructured, but then again just about any
construct can be abused to make code unstructured including
while, for, do and if.
It's all a matter of taste and style. As my teams and I use Test Driven
Development, code is refactored often, so any construct that causes
problems with this isn't appropriate.
I've never actually *used* goto in any of my code (well, maybe
once :-) but as a maintainer I see "goto error_exit" all the
time in code that is reasonably easy to read.
Ah, the truth emerges!

--
Ian Collins.
Jul 4 '06 #49

P: n/a
In article <03**********************@math.usc.edu>,
Ronald Bruck <br***@math.usc.eduwrote:
>I am reminded of an article I read at the height of the "GOTO"
controversy, way back in the 1970's: the author proposed
(tongue-in-cheek) a "COMEFROM" instruction. And he gave an example to
compute the factorial of 3.

The problem with the "COMEFROM" obstruction, of course, is that you had
^^^^^^^^^^^
Was that supposed to be "abstraction", or was it intentional?
(Either way, I like it.)
>to scan THE ENTIRE REST OF THE CODEBASE to see if you were supposed to
divert to that instruction. His sample program to compute 3! was the
worst spaghetti I ever saw.
I've actually used setjmp/longjmp to implement a COME FROM in production
code. We had a program that knew how to shut down on a request from
another program, and we wanted to run it without having to start it from
a particular program (so that we could put it on another system) but
still start/stop the processing on request from the main control program.

There was a single function that did cleanup and exited, and it turned out
to be easiest to make sure everything that could end up invoking that was
longjmp-clean and just replace the cleanup-and-terminate with making sure
the internal state was in a known-sane condition and longjmping to just
after the one-time initialization and before the wait for a wake-up call.

(I've had at least two people try to tell me they had a better way.
I'm sure there is one, but neither of them had come up with it.
The original exit code could be called, through about three layers of
support functions, from anywhere the program spent significant amounts
of wall-clock time, so there wasn't any clean way to just fall out of
the main loop when it was time to go back to the beginning, and the
absence of a working time machine made it impossible take this design
change into consideration when the program was designed that way.)
Of course, using setjmp/longjmp is Rather Easier to implement and to
work with than a fully unconstrained COME FROM. Perhaps instead of
describing longjmp as a less-restricted goto, we should be describing
setjmp as a more-restricted COME FROM.
dave

--
Dave Vandervies dj******@csclub.uwaterloo.ca
Go not to comp.lang.c for answers, for they will say both "no" and "no".
And "perhaps" and "it depends". Sometimes "yes". --Chris Dollin in
"No" seems to be the most appropriate answer in this case. \ CLC
Jul 12 '06 #50

53 Replies

This discussion thread is closed

Replies have been disabled for this discussion.