Is goto Still Considered Harmful?

Discussion in 'C Programming' started by Lynn McGuire, Mar 12, 2014.

  1. To me, the purpose of unit testing is to prove the code is correct (as
    defined by the design docs), and one cannot prove a function is correct
    until you've proven that all the functions it _calls_ are correct. I've
    chased down too many bugs where function X calls function Y with an
    invalid argument and got a result that seemed reasonable--until one day
    (or once in a blue moon) it didn't. If you test function Y, that's one
    less thing to worry about when testing (or troubleshooting) function X.
    Fair enough, though I think of "large" in terms of complexity rather
    than absolute size. A short, complex function can test my mental limits
    more than a long, simple one; the former is also more likely to contain
    hidden bugs, and that seems like inherently bad design.

    For an example, just look at the IOCCC; most submissions are mercifully
    short yet more mentally taxing than a typical real-world program that's
    ten or even a hundred times their size. And I still don't understand
    that "RSA in 5 lines" Perl T-shirt, which puts even most IOCCC code to
    shame.

    S
     
    Stephen Sprunk, Apr 4, 2014
    1. Advertisements

  2. Lynn McGuire

    Stefan Ram Guest

    Obviously tests can never prove that code is correct.
     
    Stefan Ram, Apr 4, 2014
    1. Advertisements

  3. Lynn McGuire

    James Kuyper Guest

    True, but if Y can only be called by X, that doesn't prevent you from
    testing Y; it just means that you have to test Y by calling X. I've
    written more than a few such test drivers. In my experience, if there's
    a good reason for giving Y internal linkage, the fact that it's not
    directly callable by the test driver is seldom a serious barrier to
    testing it.

    ....
    I can agree with that; greater size allows greater complexity, but it
    does not mandate it. However, as I said earlier, most of the
    uncomplicated large functions I've ever seen were either reading into or
    writing from badly designed data structures.
    Does the expanded version with annotations at the bottom of
    <http://www.cypherspace.org/rsa/pureperl.html> help? I haven't bothered
    to try to understand it, but it doesn't look that bad (unless you don't
    know perl, of course).
     
    James Kuyper, Apr 4, 2014
  4. Lynn McGuire

    Stefan Ram Guest

    Once I was assigned to write a C++ interface to a specific
    database. I started by writing a class for each table.

    Someone who saw my code was horrified by the »unnecessary
    complexity« of my code.

    It seems to me that he measured complexity by »number of
    classes«. Since I had written many classes that was a lot of
    complexity to him.

    I measured complexity by »number of rules«. I had one rule:
    »One class per table with the name of the class being the
    name of that table.« So, to me, the complexity was very low.
     
    Stefan Ram, Apr 4, 2014
  5. Lynn McGuire

    Ian Collins Guest

    I hope you won that one!

    I've seen too many cases in both C and C++ where the database is the
    "object" and not the database contents.
     
    Ian Collins, Apr 5, 2014
  6. Lynn McGuire

    Ian Collins Guest

    The complexity is inherent in the problem. If your database has a
    hundred tables, whether you choose to have mega database instance with a
    thousand functions or a hundred content focused instances with ten
    functions you still have the same complexity. How you manage the
    complexity and express the interface to the content is the art of design.

    If my client module only cares about the data in tables 36 and 42, I
    know which style of interface I prefer to have to understand.
     
    Ian Collins, Apr 5, 2014
  7. You can only thoroughly test Y if you can prod X into calling Y with all
    possible (or at least interesting) values. If X is well-written, it may
    reject or avoid bug-triggering values before they get passed to Y, so
    you don't know Y can actually handle them (i.e. fail) correctly, and you
    don't get to test X's handling of Y's failure.
    That's one common case, but not the only one I've encountered.
    I've seen the annotations and they do help, but it's complex enough that
    I can't keep the entire thing in my head at once. That was necessary to
    fit it on a T-shirt (or signature), but in another context it'd be bad
    design.

    S
     
    Stephen Sprunk, Apr 9, 2014
  8. Lynn McGuire

    James Kuyper Guest

    As I said above, I consider X and Y to be a single routine for purposes
    of testing. I seen no practical distinction between:

    int X1(int a; int b)
    {
    if(b)
    return a/b;
    else
    return INT_MAX;
    }

    and

    static int Y(a, b) { return a/b; }

    int X2 (int a; int b)
    {
    if(b)
    return Y(a,b);
    else
    return INT_MAX;
    }

    Y(1,0) would fail; but I don't consider that a defect, since Y() has
    internal linkage, and no pointer to Y() is ever passed out of the same
    translation unit (TU) where it is defined. Therefore, it can only be
    called from within the same TU. Every call to Y() from within the same
    TU is protected against having the second argument be 0, so Y() is
    relieved of it's responsibility for validating b.

    Therefore, I would consider a complete unit test of X1() to also be an
    entirely acceptable unit test for X2()+Y(), even though there's no way
    for the test driver to call Y(1,0).

    This is obviously a simplified example, merely to explain the
    equivalence I'm talking about; it is NOT intended to demonstrate a
    plausible reason for creating Y() - there is no such reason in this
    example. Almost identical blocks of code occurring in several different
    locations within X(), and nowhere else, is one typical situation where I
    would split off a separate static function for such purposes.
     
    James Kuyper, Apr 9, 2014
  9. A common real example is

    void setpixel(unsigned char *image, int width, int height, int x, int y, colour col)

    and

    void setpixel_checked(unsigned char *image, int width, int height, int x, int y, colour col)

    tests for out of bounds are often quite expensive.
     
    Malcolm McLean, Apr 9, 2014
  10. Lynn McGuire

    Phil Carmody Guest

    Phil Carmody, May 22, 2014
  11. Lynn McGuire

    Phil Carmody Guest

    Still a code monkey, and I like it that way. I've finally completed
    the cycle of company sizes (peaking at Samsung last year, yikes),
    and am now back at the beginning again, in a company with only 4
    devs and a management hierarchy that only a mathematician would be
    prepared to actually call a "hierarchy".

    Is that email address valid, I have a small favour to ask?

    Phil
     
    Phil Carmody, May 22, 2014
  12. Lynn McGuire

    Ian Collins Guest

    Yes, I just checked it for the first time this year!
     
    Ian Collins, May 22, 2014
    1. Advertisements

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 (here). After that, you can post your question and our members will help you out.