when GOTO makes sense.

Discussion in 'C Programming' started by Debashish Chakravarty, Nov 29, 2003.

  1. Debashish Chakravarty, Nov 29, 2003
    #1
    1. Advertising

  2. Debashish Chakravarty wrote:

    > K&R pg.66 describes two situations when using goto makes sense. Has
    > anyone here come across situations where using goto provided the most
    > elegant solution.
    >


    Yes. Sometimes when...

    1. There is code with a lot of resource allocation and/or semaphores
    being held and...

    2. There are many potential points of failure and...

    3. The resources need to be freed in a very precise order on failure...

    .... goto usage can be the most elegant solution.


    Because of #1 it's very important to prevent resource leaks and/or
    deadlocks. #2 makes it problematic and error prone (for maintenence
    programmers) to do:

    if(error_condition) {
    free(a);
    free(b);
    unlock(c);
    unlock(d);
    free(e);
    return -1;
    }

    at every point where a failure may occur (there may be 10 of them, and
    each may be subtly different). It may be better to have something like:
    (again, only a contrived example, assuming a, b, c, e are initialize
    to NULL, etc)


    if(error_condition)
    goto err;

    /*...*/

    err:
    /* Order important !! */
    if(a) free(a);
    if(b) free(b);
    if(c) free(c);
    unlock(c); /* must unlock c before d */
    unlock(d); /* must unlock d before free(e) */
    if(e) free(e);
    return -1;
    }


    Mark F. Haigh
    Mark F. Haigh, Nov 29, 2003
    #2
    1. Advertising

  3. Debashish Chakravarty

    Paul Hsieh Guest

    Debashish Chakravarty <> wrote:
    > K&R pg.66 describes two situations when using goto makes sense. Has
    > anyone here come across situations where using goto provided the most
    > elegant solution.


    The classic case is breaking out of a nested loop from the inside.
    While people who hate goto for some reason despise such things and
    prefer having extra if-checks to account such a condition, its slower,
    and just makes your code more complicated.

    But another interesting case is with state machines. While the
    classic implementation of a state matchine is to simply put a switch
    statement inside of a while (1) { ... } loop, this has a drawback of
    requiring the switch statement to be execute on every state change (on
    modern processors this is much slower than direct gotos.) But as an
    alternative, one could simply have one switch statement and rather
    than breaks at the end of each case block, simply have gotos to the
    blocks that represent the state transition. You have to have labels
    that are redundant with the case ...: statements, however this
    solution is much faster, and doesn't require that you maintain a state
    variable (since the state itself would be redundant with the case
    clause that was being executed at any one time) for all states (just
    entry and exit of the state machine.)

    Finally sometimes its best, for performance reasons to start a loop in
    the middle of the body of the loop rather than a start. So you have a
    goto just before your do {...} while or for() loop to enter in the
    middle of it.

    These are probably the most interesting marginal cases where using
    goto is the best solution in the C language. The problem is that
    there are many other uses of goto which are really really bad. So
    much so that people have railed against its usage, and will actually
    choose not to do so in any situation. They will lose performance
    and/or make their code complicated in all of the above cases. So this
    *should* make a good case for improving improving the language so that
    these operations can be done *without* goto (for example <break n;> to
    jump out of n nested blocks, and <continue case ___;> to jump to a
    case within the nearest enclosing switch scope.) However, I don't
    know if the C standards committee is open to suggestions such as
    these.

    --
    Paul Hsieh
    http://www.pobox.com/~qed/
    http://bstring.sf.net/
    Paul Hsieh, Nov 29, 2003
    #3
  4. Debashish Chakravarty

    Michael B. Guest

    On Sat, 29 Nov 2003 06:00:40 -0800, Paul Hsieh wrote:

    >
    > But another interesting case is with state machines. While the
    > classic implementation of a state matchine is to simply put a switch
    > statement inside of a while (1) { ... } loop, this has a drawback of
    > requiring the switch statement to be execute on every state change (on
    > modern processors this is much slower than direct gotos.) But as an
    > alternative, one could simply have one switch statement and rather
    > than breaks at the end of each case block, simply have gotos to the
    > blocks that represent the state transition. You have to have labels
    > that are redundant with the case ...: statements, however this
    > solution is much faster, and doesn't require that you maintain a state
    > variable (since the state itself would be redundant with the case
    > clause that was being executed at any one time) for all states (just
    > entry and exit of the state machine.)
    >


    Hmm, I've always implemented state machines with function pointers, like
    so:
    .... in the header:
    typedef void * (*state) (int);
    .... in main.c:
    while (ch = getnewinput()) {
    current = (state)(*current)(ch);
    }
    }
    .... example state: ( this is a very simple DFA )
    void *
    green (int input) {
    switch (input) {
    case 'A':
    printf("LIGHTS OFF\n");
    return &other;
    break;
    case 'B':
    printf("LIGHTS OFF\n");
    return &initial;
    break;
    }
    }

    Of course, casting function pointers to void and back can lead to
    undefined behavior on certain architectures (though I've verified that
    this code works on x86 and PPC). But doesn't this seem like a better
    solution (and definitely more functional, seeing as it basically emulates
    the workings of a functional language), than using gotos?

    --
    Mike's Patented Blocklist; compile with gcc:

    i=0;o(a){printf("%u",i>>8*a&255);if(a){printf(".");o(--a);}}
    main(){do{o(3);puts("");}while(++i);}
    Michael B., Nov 30, 2003
    #4
  5. In article <>,
    "Michael B." <> wrote:

    > Of course, casting function pointers to void and back can lead to
    > undefined behavior on certain architectures (though I've verified that
    > this code works on x86 and PPC). But doesn't this seem like a better
    > solution (and definitely more functional, seeing as it basically emulates
    > the workings of a functional language), than using gotos?


    It leads to undefined behavior, that's it. So that makes it in the eyes
    of most people a very bad solution, definitely worse than using goto.

    It also mixes up "states" and "implementation of code to handle the
    action in a given state". Each of your functions doesn't return a state,
    it returns a pointer to the code to be executed in that state.

    And it adds significantly to the number of lines of code to be written.
    In most state machines, the code for each state is quite trivial, so
    adding a few lines for every state adds significantly to the lines of
    code.
    Christian Bau, Nov 30, 2003
    #5
  6. "Mark F. Haigh" <> wrote in message news:<zFUxb.61536$>...
    > Debashish Chakravarty wrote:
    > > anyone here come across situations where using goto provided the most
    > > elegant solution.

    > Yes. Sometimes when...
    > 2. There are many potential points of failure and...
    > 3. The resources need to be freed in a very precise order on failure...


    These gotos may sometimes be avoided by replacing
    if (! step7())
    goto backout7;
    if (! step8())
    goto backout8;
    ...
    with
    if (step7()) {
    if (step8()) {
    ...
    }
    }
    but the cure may be worse than the disease
    if there are many levels of nesting.

    Another frequent case where goto is better than the alternative is
    for (Search; unfinished;) {
    for (Subsearch; unfinished;) {
    if (WE_WON) {
    celebrate();
    goto persevere;
    }
    }
    }
    lament();
    persevere: ;

    (Even when loops are not nested, a ``break'' is not quite
    enough to avoid this ``goto.'')

    I use very few gotos in *final* code, but when cranking out
    fresh code, I sometimes write ``goto start_over'' and then decide
    later, when I see the full logic, whether to rewrite the loop as
    ``do'', ``while'' or ``for.'' (In other words, the goto-less
    version will be more *readable*, but the *goto* is more *writable*.)

    Finally, let me mention my Favorite Goto (tm):
    http://freepages.genealogy.rootsweb.com/~jamesdow/Tech/dbldum.htm

    If one needs to make major changes to the Favorite Goto program,
    getting rid of the goto might be the first step, but as is,
    it possesses, IMO, a beautiful elegance no non-GOTO version
    will have. Can you construct a goto-less equivalent that is
    in the same ballpark for speed and readability?

    (I have posted the Favorite Goto before on Usenet, receiving
    some suggestions which made no sense. Please code, compile and
    test your version before sending it to me.)

    James
    James Dow Allen, Dec 1, 2003
    #6
  7. Debashish Chakravarty

    Dan Pop Guest

    In <> Debashish Chakravarty <> writes:

    >K&R pg.66 describes two situations when using goto makes sense. Has
    >anyone here come across situations where using goto provided the most
    >elegant solution.


    'Elegant' is in the eye of the beholder. I prefer to speak in terms of
    readable code. The code readability decreases exponentially when the
    number of nested control structures increases linearly. If a goto can
    avoid an additional nesting level, than that goto is probably a "good"
    goto. Of course, this is not the only technique for minimising the number
    of nested control structures in a function, but one shouldn't
    automatically discard it on religious grounds.

    Dan
    --
    Dan Pop
    DESY Zeuthen, RZ group
    Email:
    Dan Pop, Dec 1, 2003
    #7
  8. Debashish Chakravarty

    Ed Morton Guest

    James Dow Allen wrote:

    <snip>
    > Finally, let me mention my Favorite Goto (tm):
    > http://freepages.genealogy.rootsweb.com/~jamesdow/Tech/dbldum.htm
    >
    > If one needs to make major changes to the Favorite Goto program,
    > getting rid of the goto might be the first step, but as is,
    > it possesses, IMO, a beautiful elegance no non-GOTO version
    > will have. Can you construct a goto-less equivalent that is
    > in the same ballpark for speed and readability?


    This MAY (or may not) be the most efficient piece of code on the planet,
    but this has to be some of the worst code I've ever seen for
    readability. In particular, jumping back and forth between the bodies of
    2 separate pairs of nested "for" loops using "goto"s is horrible, and
    then having compound conditions like this in a loop:

    for (tnum = won = success = 0;
    success ? ++won < need : won + ohsize >= need + tnum;
    tnum++, P++, success = IS_CONT(pwin)) {

    is just ridiculuous too.

    By the way, the program hangs on the second sample input provided on the
    web site. I would debug it, but I don't want to take the time to
    understand it ;-). Ditto for providing a non-goto alternative.

    I'm not 100% against gotos, I've just never seen code that uses gotos
    that I personally find more readable than the equivalent without gotos.
    I recently wrote a short (200 lines or so) program using gotos just to
    see if I could learn to appreciate the benefits wrt error-handling, but
    once the error-handling became even moderatly complex (i.e. realisitc!)
    the initial simplicity afforded by the gotos fell away. I looked at your
    code hoping to learn a good way to use goto for readability.

    Ed.
    Ed Morton, Dec 1, 2003
    #8
  9. On Mon, 1 Dec 2003 05:13:10 UTC, (James Dow
    Allen) wrote:

    > I use very few gotos in *final* code, but when cranking out
    > fresh code, I sometimes write ``goto start_over'' and then decide
    > later, when I see the full logic, whether to rewrite the loop as
    > ``do'', ``while'' or ``for.'' (In other words, the goto-less
    > version will be more *readable*, but the *goto* is more *writable*.)


    > Finally, let me mention my Favorite Goto (tm):
    > http://freepages.genealogy.rootsweb.com/~jamesdow/Tech/dbldum.htm


    Looks more obscure than needed. A better structure is required.

    Use functions to encapsulate details from the flow.
    Using the the same functions would remove any need for goto as side
    effect.
    You've written some loops looking exactly identical. Buildng fuctions
    would remove the details from the flow and lets them reused.

    Programming starts with design, not hacking.
    A well designed program has not a single function but many of them,
    each not longer than about 50 lines, doing one specific task. Not
    more, not less.

    A task gets splitted in What is to do and how is it done. This makes
    debugging more easy, helps to understund the flow and is at least more
    readable as such a hack as you'd produced.

    > If one needs to make major changes to the Favorite Goto program,
    > getting rid of the goto might be the first step, but as is,
    > it possesses, IMO, a beautiful elegance no non-GOTO version
    > will have. Can you construct a goto-less equivalent that is
    > in the same ballpark for speed and readability?


    A side effect would be that there is no goto in the whole program.
    That is because the need of goto gets superflous by design.

    --
    Tschau/Bye
    Herbert

    To buy eComStation 1.1 in germany visit http://www.pc-rosenau.de
    The Real OS/2 Guy, Dec 1, 2003
    #9
  10. Debashish Chakravarty

    Alan Balmer Guest

    On Fri, 28 Nov 2003 22:08:10 -0500, Debashish Chakravarty
    <> wrote:

    >K&R pg.66 describes two situations when using goto makes sense. Has
    >anyone here come across situations where using goto provided the most
    >elegant solution.


    Yes.

    --
    Al Balmer
    Balmer Consulting
    Alan Balmer, Dec 1, 2003
    #10
  11. Debashish Chakravarty

    Paul Hsieh Guest

    "Michael B." <> wrote:
    > On Sat, 29 Nov 2003 06:00:40 -0800, Paul Hsieh wrote:
    > > But another interesting case is with state machines. While the
    > > classic implementation of a state matchine is to simply put a switch
    > > statement inside of a while (1) { ... } loop, this has a drawback of
    > > requiring the switch statement to be execute on every state change (on
    > > modern processors this is much slower than direct gotos.) But as an
    > > alternative, one could simply have one switch statement and rather
    > > than breaks at the end of each case block, simply have gotos to the
    > > blocks that represent the state transition. You have to have labels
    > > that are redundant with the case ...: statements, however this
    > > solution is much faster, and doesn't require that you maintain a state
    > > variable (since the state itself would be redundant with the case
    > > clause that was being executed at any one time) for all states (just
    > > entry and exit of the state machine.)

    >
    > Hmm, I've always implemented state machines with function pointers, like
    > so:


    Function pointers, computed gotos (for gcc fans) and switch statements
    are all roughly the same speed -- i.e., they are all slow pipeline
    serializing bottlenecks in modern microprocessors (since the predictor
    is likely to be wrong.) And once again, with your array of function
    pointers strategy requires that you maintain an index as you do state
    transitions. Worse yet, you have to write a bunch of little
    function-lets just to handle single state handling and state
    transitions.

    Your solution is fine from a functionality point of view, but still
    cannot hold a candle to a sequence of hand coded gotos in terms of
    performance, and even compactness (since you avoid state index
    maintence.) The only disadvantage of my method are the hugely
    redundant case and goto labels. (You can of course clean this up a
    bit with macros.)

    > [...] Of course, casting function pointers to void and back can lead to
    > undefined behavior on certain architectures (though I've verified that
    > this code works on x86 and PPC).


    Of course nobody is going to bother you about doing this, even the
    group jumped on me when I magicallly coerced a void * into a FILE *
    which apparently fails on like 3 obscure machines in the whole world
    that noone has ever heard of (and upon which none can read USENET
    news.)

    > [...] But doesn't this seem like a better
    > solution (and definitely more functional, seeing as it basically emulates
    > the workings of a functional language), than using gotos?


    No ... not unless you were trying to construct state machines on the
    fly. And that doesn't come up unless you are trying to do something
    like regular expression parsing -- but in those cases I would think
    that special casing would tend to still win over such an overly
    general method such as you describe.

    --
    Paul Hsieh
    http://www.pobox.com/~qed/
    http://bstring.sf.net/
    Paul Hsieh, Dec 1, 2003
    #11
  12. Debashish Chakravarty

    Damn Skippy Guest

    On Mon, 01 Dec 2003 11:25:41 -0600, Ed Morton
    <> wrote:

    >I'm not 100% against gotos, I've just never seen code that uses gotos
    >that I personally find more readable than the equivalent without gotos.
    >I recently wrote a short (200 lines or so) program using gotos just to
    >see if I could learn to appreciate the benefits wrt error-handling, but
    >once the error-handling became even moderatly complex (i.e. realisitc!)
    >the initial simplicity afforded by the gotos fell away. I looked at your
    >code hoping to learn a good way to use goto for readability.
    >
    > Ed.


    instead of using 'break' in the pseudocode below, i would prefer using
    'goto'. Suggestions appreciated. This avoids testing a variable we
    just set (in the event something failed). "var is false. Is var
    true?" If there is only one label, it seems very readable to me. It
    clearly outlines which parts of the code will not be executed if
    something fails. The if() test around process(); suggests at first
    glance that it may or may not be executed on an error-free pass,
    depending on some other condition. Using goto and keeping process()
    from being buried keeps this much more clear. It depends on the
    situation of course.

    To me,

    if ( a) { ... }

    reads the same as

    if (!a) goto skip_this; { ... } skip_this:

    especially, and i will be flamed for this, if you consider the opcodes
    which will be generated, on the actual real tangible machine(s) on
    which it will run. When you think of it this way, it doesn't matter
    whether you use goto or not, cos the CPU will (i.e. JUMP type of
    instruction).

    So you must decide what is readable, and what other people will think
    is readable. Bottom line - if people keep asking you why you have all
    those 'goto' statements, it's time to cut back.

    Remember, C code will be:
    1) compiled and executed or
    2) interpreted or
    3) in a textbook, hopefully with rules and exceptions


    ============ inefficient, inelegant, recommended ===========

    for ( .. ) {
    if ( a != b ) {
    good=false;
    complain();
    break;
    }
    }

    if (good) {
    process();
    }

    cleanup_regardless:
    cleanup();

    ============ better? saves one test and one stack variable ===========

    for ( .. ) {
    if ( a != b ) {
    complain();
    goto cleanup_regardless;
    }
    }

    process();

    cleanup_regardless:
    cleanup();

    ============ ===========

    of course, i hope i never see gotos in something like:

    if ( (fp = fopen(szFilename)) != NULL ) {
    if ( fread (&buf, 1, len, fp) == len ) {
    if ( !strncmp ( buf, 4, "JFIF") ) {
    process_jfif();
    }
    }
    }
    Damn Skippy, Dec 2, 2003
    #12
  13. Debashish Chakravarty

    Ed Morton Guest

    Damn Skippy wrote:
    <snip>
    > instead of using 'break' in the pseudocode below, i would prefer using
    > 'goto'.


    A break (or a continue) is just a goto in disguise. In some ways they're
    worse - at least a goto has a label associated with it which you can
    give a meaningful name. I never use either, except, of course, break in
    a switch statment.

    Suggestions appreciated.

    Since you asked...

    <snip>

    > So you must decide what is readable


    That's what I'm after. In most code, I'll cheerfully accept a very small
    performance impact in exchange for even a very small gain in readability.

    > ============ inefficient, inelegant, recommended ===========


    I'd never recommend this....

    > for ( .. ) {
    > if ( a != b ) {
    > good=false;
    > complain();
    > break;
    > }
    > }
    >
    > if (good) {
    > process();
    > }
    >
    > cleanup_regardless:
    > cleanup();
    >
    > ============ better? saves one test and one stack variable ===========


    Yes, if modified as described further down in my response.

    > for ( .. ) {
    > if ( a != b ) {
    > complain();
    > goto cleanup_regardless;
    > }
    > }
    >
    > process();
    >
    > cleanup_regardless:
    > cleanup();
    >
    > ============ ===========


    What both of the above are missing is an explicit statement of what gets
    you out of the "for" loop, so the next person to work on this code has
    no help in understanding what this VERY IMPORTANT condition is that
    suddenly changes flow control. Assuming that "a != b" means that the
    processor is in overload, I'd write it as something like:

    olvdState = STABLE;
    for ( ..; .. && ovldState == STABLE; .. ) {
    if ( a != b ) {
    ovldState = OVERLOADED;
    complain();
    }
    }

    if (ovldState = STABLE) {
    process();
    }

    cleanup();

    If you had written your goto-version like this:

    for ( ..; ..; .. ) {
    if ( a != b ) {
    complain();
    goto overloaded;
    }
    }

    process();

    overloaded:
    cleanup();

    then it's pretty close to the version I wrote without gotos in that it
    explicitly tells the reader WHY you're leaving the loop (as opposed to
    just what you're going to do after you leave the loop, which is already
    clear from the "cleanup()" function name) and yes, I think it's better
    than your original version that uses a break.

    The main reason I prefer the version that uses a variable is that it
    forces the original code author to explicitly state the VERY IMPORTANT
    loop exit conditions so the next reader isn't fooled into thinking they
    know exactly why the loop terminates until they're in the middle of the
    loop and suddenly come across an unexpected, probably unnamed, loop exit.

    Sure it's a little more work for the original author to come up with
    good names for the variable and it's values, but that's better than the
    next guy having to potentially take much longer to have to figure out
    that abstraction, possibly under customer pressure to fix or enhance
    that and/or other code.

    People using gotos typically (but, I assume, not always) create their
    labels based on WHAT they're doing at that labelled point rather than
    WHY they're doing it. Not being a goto officianado, I can't decide if
    that's the right thing to do with a goto or not - you'd end up with more
    labels if you use the "WHY" (e.g. since there could be many reasons for
    going to a "cleanup" routine) but IMHO you'd have more readable code.

    > of course, i hope i never see gotos in something like:
    >
    > if ( (fp = fopen(szFilename)) != NULL ) {
    > if ( fread (&buf, 1, len, fp) == len ) {
    > if ( !strncmp ( buf, 4, "JFIF") ) {
    > process_jfif();
    > }
    > }
    > }
    >


    Then don't look at the URL posted elsethread (shudder...) ;-).

    Ed.
    Ed Morton, Dec 2, 2003
    #13
  14. Ed Morton <> wrote in message news:<bqftim$>...
    > James Dow Allen wrote:
    > > Finally, let me mention my Favorite Goto (tm):
    > > http://freepages.genealogy.rootsweb.com/~jamesdow/Tech/dbldum.htm

    >
    > This MAY (or may not) be the most efficient piece of code on the planet,
    > but this has to be some of the worst code I've ever seen for
    > readability. In particular, jumping back and forth between the bodies of
    > 2 separate pairs of nested "for" loops using "goto"s is horrible,


    Is it really as horrible as it seems? Putting verb participles at the
    ends of sentences seems wrong to Englishmen but normal to a German.

    I'll certainly admit the structure is bizarrely unusual, but personally I
    find it bizarrely elegant! It works only because the two loops manipulate
    the same variables in exactly the same way, but once you understand this
    fact, it makes sense.

    But let me emphasize one key point: The problem this program solves
    is non-trivial. *Any* program to solve the problem will take time
    to understand. The question isn't whether my program takes a while
    to understand, but how that time compares with an efficient alternative
    to *solve the same problem.*

    It did not take me long to write this program, and many people have
    downloaded it for its intended application. Does no one care to invest
    a little time to prove there is an efficient readable alternative?

    > then having compound conditions like this in a loop:
    >
    > for (tnum = won = success = 0;
    > success ? ++won < need : won + ohsize >= need + tnum;


    I could have added comments, but the C isn't too opaque.
    Reading left to right,
    did contractors SUCCESS-fully win the trick? If so, increment the
    number of tricks they've WON and compare it with the number they NEED
    for their contract....
    > tnum++, P++, success = IS_CONT(pwin)) {
    >
    > is just ridiculuous too.


    Perhaps I should enter it in the Obfuscated C contest. :)
    I often provide newlines to break up such long expressions; would
    that address your complaint? Is an expression terminated with
    comma *really* harder to understand than one terminated with semicolon?

    > By the way, the program hangs on the second sample input provided on the
    > web site.


    How long did you let it run? Experts spend hours on that puzzle
    without getting it, I hope you gave your Pentium a few minutes.
    This is the first failure report I've had; I'd appreciate a core dump.

    Someone else wrote:
    > Looks more obscure than needed. A better structure is required.


    No question that this 200-line program is much harder to understand
    than a typical 500-line program, but that's not the proper question.

    The question is, how does its difficulty compare with an alternative
    program *that solves the same problem.* Since my program provides
    all the necessary algorithm details, I do not believe rewriting the
    program is a significant challenge to a good programmer.

    When someone demonstrates a working program almost as efficient and
    more readable than mine, I'll "eat my hat." Until then, your words
    are just idle pedantry.

    James
    James Dow Allen, Dec 3, 2003
    #14
  15. Debashish Chakravarty

    Ed Morton Guest

    James Dow Allen wrote:
    <snip>
    > It did not take me long to write this program, and many people have
    > downloaded it for its intended application. Does no one care to invest
    > a little time to prove there is an efficient readable alternative?


    It's not a little time. I'm sure my total lack of knowledge about bridge
    doesnt help, but that's kinda my point.

    >>then having compound conditions like this in a loop:
    >>
    >> for (tnum = won = success = 0;
    >> success ? ++won < need : won + ohsize >= need + tnum;

    >
    >
    > I could have added comments, but the C isn't too opaque.
    > Reading left to right,
    > did contractors SUCCESS-fully win the trick? If so, increment the
    > number of tricks they've WON and compare it with the number they NEED
    > for their contract....
    >
    >> tnum++, P++, success = IS_CONT(pwin)) {
    >>
    >>is just ridiculuous too.

    >
    >
    > Perhaps I should enter it in the Obfuscated C contest. :)
    > I often provide newlines to break up such long expressions; would
    > that address your complaint?


    No, some well-named intermediate variables, functions and/or macros
    would address my complaint.

    Is an expression terminated with
    > comma *really* harder to understand than one terminated with semicolon?


    No. It was the loop termination condition that was the hardest to
    understand. I don't mean I can't read the C, I just don't know what the
    abstraction is for the C (i.e. what it "means").

    >>By the way, the program hangs on the second sample input provided on the
    >>web site.

    >
    >
    > How long did you let it run? Experts spend hours on that puzzle
    > without getting it, I hope you gave your Pentium a few minutes.
    > This is the first failure report I've had; I'd appreciate a core dump.


    I was wrong, it doesn't hang. It does just take a few minutes. Since the
    first sample terminated within about a second, I expected the second to
    do the same. Perhaps a warning about that on the web page and/or
    progress reports from the tool would be useful?

    > Someone else wrote:
    >
    >>Looks more obscure than needed. A better structure is required.

    >
    >
    > No question that this 200-line program is much harder to understand
    > than a typical 500-line program, but that's not the proper question.
    >
    > The question is, how does its difficulty compare with an alternative
    > program *that solves the same problem.* Since my program provides
    > all the necessary algorithm details, I do not believe rewriting the
    > program is a significant challenge to a good programmer.


    But it does provide a significant challenge because it's missing all the
    abstractions for what the code is doing, so someone who doesn't know the
    domain can read the code and understand what's happening to the
    variables, etc., but not why it's happening and without the relevant
    domain expertise couldn't come up with the right abstractions for a good
    modified version of the code.

    > When someone demonstrates a working program almost as efficient and
    > more readable than mine, I'll "eat my hat."


    Well, if you decomposed what you have into a few small functions (with
    their own local variables rather than just the slew of them at the start
    of "main()" being promoted to global) and provided some good, abstract
    comments, then you'd stand an excellent chance of getting a meal ;-).

    Until then, your words
    > are just idle pedantry.


    You can dismiss my comments if you like, but I wasn't pedantic about
    anything. I didn't say anything like "this code uses goto and therefore
    is bad" I said "This code is hard to read, and here's some examples of why".

    Ed.

    > James
    Ed Morton, Dec 3, 2003
    #15
  16. Debashish Chakravarty <> wrote in message news:<>...
    > K&R pg.66 describes two situations when using goto makes sense. Has
    > anyone here come across situations where using goto provided the most
    > elegant solution.


    Another very useful case:

    if (..complex stuff..) {
    do_something ();
    if (...other complex stuff) goto eelse;
    ... do stuff ...
    } else eelse: {
    ... do the else case ...
    }

    Once you do this, you'll want to do it all the time.
    stelios xanthakis, Dec 3, 2003
    #16
  17. Debashish Chakravarty

    Ed Morton Guest

    stelios xanthakis wrote:
    > Debashish Chakravarty <> wrote in message news:<>...
    >
    >>K&R pg.66 describes two situations when using goto makes sense. Has
    >>anyone here come across situations where using goto provided the most
    >>elegant solution.

    >
    >
    > Another very useful case:
    >
    > if (..complex stuff..) {
    > do_something ();
    > if (...other complex stuff) goto eelse;
    > ... do stuff ...
    > } else eelse: {
    > ... do the else case ...
    > }


    This is clearer:

    status = INCOMPLETE;
    if (..complex stuff..) {
    do_something ();
    if (! ...other complex stuff) {
    ... do stuff ...
    status = COMPLETE;
    }
    }
    if (status == INCOMPLETE) {
    ... do the else case ...
    }

    Of course, In a real program I'd have a variable name and values that
    accurately reflect the abstract conditions that are true at both of the
    assignment points for "status" above.

    > Once you do this, you'll want to do it all the time.


    Not really.

    Ed.
    Ed Morton, Dec 4, 2003
    #17
  18. Ed Morton <> wrote in message news:<bqmbca$>...
    > stelios xanthakis wrote:
    > > Debashish Chakravarty <> wrote in message news:<>...
    > >
    > >>K&R pg.66 describes two situations when using goto makes sense. Has
    > >>anyone here come across situations where using goto provided the most
    > >>elegant solution.

    > >
    > >
    > > Another very useful case:
    > >
    > > if (..complex stuff..) {
    > > do_something ();
    > > if (...other complex stuff) goto eelse;
    > > ... do stuff ...
    > > } else eelse: {
    > > ... do the else case ...
    > > }

    >
    > This is clearer:
    >
    > status = INCOMPLETE;
    > if (..complex stuff..) {
    > do_something ();
    > if (! ...other complex stuff) {
    > ... do stuff ...
    > status = COMPLETE;
    > }
    > }
    > if (status == INCOMPLETE) {
    > ... do the else case ...
    > }


    Right. Only "problem" is that now we have two statements (actually 3 statements
    and a variable). So everything has to be enclosed in { } if the above
    is, say, the body of a for(;;).
    This is a personal preference of course with little practical use.

    Stelios
    stelios xanthakis, Dec 4, 2003
    #18
  19. Debashish Chakravarty

    Ed Morton Guest

    stelios xanthakis wrote:
    > Ed Morton <> wrote in message news:<bqmbca$>...
    >
    >>stelios xanthakis wrote:

    <snip>
    >>>Another very useful case:
    >>>
    >>> if (..complex stuff..) {
    >>> do_something ();
    >>> if (...other complex stuff) goto eelse;
    >>> ... do stuff ...
    >>> } else eelse: {
    >>> ... do the else case ...
    >>> }

    >>
    >>This is clearer:
    >>
    >> status = INCOMPLETE;
    >> if (..complex stuff..) {
    >> do_something ();
    >> if (! ...other complex stuff) {
    >> ... do stuff ...
    >> status = COMPLETE;
    >> }
    >> }
    >> if (status == INCOMPLETE) {
    >> ... do the else case ...
    >> }

    >
    >
    > Right. Only "problem" is that now we have two statements (actually 3 statements
    > and a variable). So everything has to be enclosed in { } if the above
    > is, say, the body of a for(;;).


    Which it should be anyway to avoid someone in future coming along and
    adding a statement which they think is related to the "for" but actually
    falls outside it or pushes the existing code outside of it. That's a
    very common bug when modifying code that doesn't use braces on every
    loop and "if". There's been so many times I've seen something like this:

    if (x)
    y();

    get changed to:

    if (x)
    y();
    z();

    Some people write:

    if (x) y();

    to make the distincion clearer for single-statement cases, but it seems
    simpler to me to just always uses the braces (and there are implications
    for some source code control systems in a multi-user environment) and
    that doesn't apply in this particular case anyway.

    > This is a personal preference of course with little practical use.


    No, it's about increasing the clarity of your code for speed of
    understanding by the next person to enhance it and reducing the risk of
    someone in future introducing a bug when they modify it (i.e.
    "future-proofing") and it's a 100% practical technique.

    Ed.

    > Stelios
    Ed Morton, Dec 4, 2003
    #19
  20. Debashish Chakravarty

    Alan Balmer Guest

    On 4 Dec 2003 06:03:20 -0800, (stelios xanthakis)
    wrote:

    >> }
    >> if (status == INCOMPLETE) {
    >> ... do the else case ...
    >> }

    >
    >Right. Only "problem" is that now we have two statements (actually 3 statements
    >and a variable). So everything has to be enclosed in { } if the above
    >is, say, the body of a for(;;).


    And, imo, this is a good thing. Braces are free, and useful.

    --
    Al Balmer
    Balmer Consulting
    Alan Balmer, Dec 4, 2003
    #20
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    1
    Views:
    355
    Peter Otten
    Aug 30, 2006
  2. Replies:
    11
    Views:
    634
    Crouchinho
    Sep 26, 2006
  3. Replies:
    3
    Views:
    356
  4. Neroku
    Replies:
    6
    Views:
    10,175
    Chris Uppal
    Feb 8, 2007
  5. Replies:
    5
    Views:
    423
Loading...

Share This Page