Re: Cpp Considered Harmful

From: Phlip (phlip_cpp_at_yahoo.com)
Date: 08/31/04

  • Next message: Christopher Benson-Manica: "Re: Tutorial for beginner/ Tutorial voor beginner"
    Date: Tue, 31 Aug 2004 13:01:22 GMT
    
    

    Steven T. Hatton wrote:

    > Kai-Uwe Bux wrote:
    >
    > > "Read up on them"? Have you ever used this feature? Sometimes you
    realize
    > > that something is useful not from reading about it.
    >
    > There has to be some need I have before I look for something to fill it.
    > The idea of aborting a program on failure is simply not something I
    believe
    > to be a good practice.

    In a softer language, array[x] throws an exception for you if x is out of
    bounds. In a C language, you have the option to either cross your fingers
    and do nothing, override [] and throw an exception, or override [] and
    provide an assertion that only compiles without NDEBUG activated.

    The C languages need the ability to do nothing, or conditionally compile an
    exception, to compete with assembly language.

    (BTW, if you are not competing with assembly language, _don't use C++_...)

    On the test side, here's an assertion:

        #define CPPUNIT_ASSERT_EQUAL(sample, result) \
            if ((sample) != (result)) { stringstream out; \
                out << __FILE__ << "(" << __LINE__ << ") : "; \
                out << #sample << "(" << (sample) << ") != "; \
                out << #result << "(" << (result) << ")"; \
                cout << out.str() << endl; \
                OutputDebugStringA(out.str().c_str()); \
                OutputDebugStringA("\n"); \
                __asm { int 3 } }

    The stringerizer, #, converts an expression into a string, and operator<<
    formats the expression's value as a string. The macro inserts both these
    strings into a stringstream object. Both cout and OutputDebugStringA() reuse
    this object's value.

    The result, at test failure time, is this line:

        c:\...\project.cpp(56) : "Ignatz"(Ignatz) != name(Ignotz)

    <F8> takes us directly to the failing test assert statement. The assertion
    provides...

     - fault navigation - the editor takes you to the failing line
     - expression source reflected into the output
     - expression values reflected into the output
     - a breakpoint

    On a platform descended from the Intel x86 architecture, if you run these
    tests from a command line, not the editor, the OS will treat __asm { int 3 }
    as a hard error, and it will offer to raise the default debugger.

    When NDEBUG is off (what some folk call "Debug Mode"), tests can
    aggressively exercise production code, making its internal assertions safer
    to turn off.

    > Actually Stroustrup goes on to demonstrate an alternative form of
    assertion
    > which also failed to appeal to me. He uses a template that takes an
    > invariant as a parameter. And get this. It throws an exception rather
    > than aborting the program. In general that is the kind of thing I was
    > talking about, but I simply don't find cluttering my programs with
    > debugging code a good idea, nor, in general do I find it useful. I've
    > noticed C and C++ programmers new to Java tend to use stuff like if(DEBUG
    > {/*...*/} until they realize it really isn't all that useful in that
    > context.

    Aggressive testing tends to help code right-size its assertions, and
    exceptions, and hide them behind minimal interfaces. For example, this loads
    a library, pulls a function pointer out of it, and asserts it found the
    function:

                HMODULE libHandle = LoadLibrary("opengl32.dll");
                void (APIENTRY *glBegin) (GLenum mode);
                FARPROC farPoint = GetProcAddress(libHandle, "glBegin");
                assert(farPoint);
                glBegin = reinterpret_cast</something/ *> (farPoint);
              // use glBegin() like a function
                FreeLibrary(libHandle);

    The assert is not the problem here - the /something/ is. It should be this:

                glBegin = reinterpret_cast
                                <
                                void (APIENTRY *) (GLenum mode)
    > (farPoint);

    To reduce the risk, and avoid writing the complete type of glBegin() and
    every other function we must spoof more than once, we upgrade the situation
    to use a template:

            template<class funk>
            void
        get(funk *& pointer, char const * name)
        {
            FARPROC farPoint = GetProcAddress(libHandle, name);
            assert(farPoint);
            pointer = reinterpret_cast<funk *> (farPoint);
        } // return the pointer by reference

    That template resolves the high-risk /something/ for us. It collects
    glBegin's target's type automatically, puts it into funk, and reinterprets
    the return value of GetProcAddress() into funk's pointer's type. And it
    calls assert() (which could be your exception) only once, behind the get()
    interface.

    Pushing the risk down into a relatively typesafe method permits a very clean
    list of constructions for all our required function pointers:

            void (APIENTRY *glBegin) (GLenum mode);
            void (APIENTRY *glEnd) (void);
            void (APIENTRY *glVertex3f) (GLfloat x, GLfloat y, GLfloat z);

            get(glBegin , "glBegin" );
            get(glEnd , "glEnd" );
            get(glVertex3f , "glVertex3f" );

    That strategy expresses each function pointer's type-the high risk part-once
    and only once. (And note how the template keyword converts statically typed
    C++ into a pseudo-dynamic language.)

    > For the most part, I've pointed to things you /can/ do with Java and
    > you /can't/ do with C++.

    And the things we can't do in Java (stringerization, token pasting,
    conditional compilation, etc.) you decry as "bad C++ style".

    Java was invented because too many programmers not bright enough to use C or
    C++ were forced into it by schools and managers. They did not write
    'new'-free code, and did not use smart pointers where they needed a 'new'.
    So Java's inventors said, "Hey, let's tell everyone we don't permit
    pointers. Yeah, that's the ticket, pointers are bad. Oh, also we need to
    pass primitives by reference, and we need to store heterogenous arrays, and
    we need to declare exceptions at all interfaces," and they ended up doing a
    zillion extra things to the language specification that C++ lets you do
    _with_ the language.

    > How so? By introducing a more elegant, efficient, and effective means of
    > managing libraries? I know damn good and well that the Cpp is going to be
    > around for the foreseeable future. That doesn't mean I can't criticize
    its
    > use, and proposed solutions for supporting the same functionality without
    > resorting to using it.

    Please base that criticism on your direct personal experience, not on
    quoting Bjarne.

    -- 
      Phlip
      http://industrialxp.org/community/bin/view/Main/TestFirstUserInterfaces
    

  • Next message: Christopher Benson-Manica: "Re: Tutorial for beginner/ Tutorial voor beginner"

    Relevant Pages

    • Re: C++ -> XSL -> XML -> XSL -> C++
      ... >> for testing software. ... If the assertion language is rich enough, ... If the assertion language is interesting enough, ... That means to write an assertion, you don't want to do it in XML ...
      (microsoft.public.vc.language)
    • Re: URGENT! Create Database Error
      ... connection string. ... > big ugly assertion box, then that's not the problem, but if the ... > an @ at the beginning is probably confusing too since that's the ... > SQL SErver parameters but these are just variables. ...
      (microsoft.public.dotnet.framework.compactframework)
    • Re: URGENT! Create Database Error
      ... one is a file reference, and the other is the database connection string. ... big ugly assertion box, then that's not the problem, but if the assertion ...
      (microsoft.public.dotnet.framework.compactframework)
    • Re: Question about Spanish
      ... It suggests that the language is somehow ... where is the data to support your assertion in the ... Or is this a case of PC dogma first, scientific evidence ... to use degrading vocabulary of fellow humans. ...
      (sci.lang)
    • Re: Son du tonnerre
      ... On ne retrouve nulle part cette assertion. ... the language of the Internet plus international ...
      (sci.physics)