What do you think about the code?

R

Richard Heathfield

Frederick Gotham said:

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.
 
F

Frederick Gotham

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 */
}
}
}
}

}
 
R

Rouben Rostamian

Tom said:
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.
 
R

Richard Heathfield

Frederick Gotham said:

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.
 
I

Ian Collins

Frederick said:
Ian Collins posted:






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.
 
F

Flash Gordon

(e-mail address removed) wrote:

> 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.
 
A

Andrew Poelstra

Andrew Poelstra posted:




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.
 
K

Keith Thompson

Frederick Gotham said:
Andrew Poelstra posted:

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.)
 
M

Morris Dovey

Keith Thompson (in (e-mail address removed)) 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

? :)
 
R

Richard Heathfield

Keith Thompson said:

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?
 
K

Keith Thompson

Richard Heathfield said:
Keith Thompson said:



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.
 
I

Ian Collins

Keith 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:

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?
 
G

goose

Andrew said:
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;
 
G

goose

Ian said:
Frederick Gotham wrote:

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.
 
G

goose

Andrew said:
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;
 
R

Richard Heathfield

Keith Thompson said:
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.
 
I

Ian Collins

goose said:
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.
 
G

goose

Ian said:
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.

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.
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,
 
I

Ian Collins

goose said:
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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,062
Latest member
OrderKetozenseACV

Latest Threads

Top