When good code goes bad


Reason #26972593-1 why I hate C++ development:  Just fixed up some broken logic pertaining to binding names in the language service.  All tests pass when running debug, but everything fails when running free.  Normally when this happens it’s due to me not initializing a variable (what a great feature that is!) and a dummy value was picked that ended up working in debug.  For example you have something like:


if (foo == bar) {


}


And you haven’t initilized foo or bar so they both got a dummy value of something like 0xecececec.  So the test works in debug (which follows what you expected because you thought both values would be 0.  However, in retail the values are totally gibberish and it’s broken.  Determing what the actual problem is a exercise in unhappiness.  Stepping through retail code is possible, but it’s not fun.  My personal favorite is when you have code like:


if (FAILED(hr = DoSomething())) {
    return hr;
}


When you step over the call to DoSomething you’ll land on the “return hr;” line making you think that that call failed.  You then step back (or re-run) and walk through the DoSomething method to find out what failed.  It actually didn’t fail, but with all the compiler otpimizations in place what you’re probably actually seeing is the current location moving to jsut after the return and the IDE just picking an unfortunate location to say where you are.  So you’ve wasted 5 minutes trying to walk through that code only to find out that there was nothing wrong with it.  Sigh…


Oh well, some day I’ll be off this bloody language 🙂


Edit: I traced through it and it did indeed turn out to be an unintialized class field.  Why isn’t there a warning a can turn on to let me know about this?? Is there a warning that I just don’t know about??  I don’t think that there are words to express how much I love this language.


Comments (20)

  1. C# might become a better language when Graphics class becomes as good as Win32 API (no, DllImport will not do) and I will not have to call Dispose on every pen/brush/whatever which I don’t have to do in C++ (surprise). Unloading asemblies would be another useful addition.

  2. Mikhail: The using statement should call dipose for you and will allow these unmanaged resources to get cleaned up appropriately.

    I believe that unloading assemblies is something that is possible to do (at least in Whidbey).

    You ask for the graphics class to be as good as Win32. But isn’t that exactly what DllImport gets you? Direct access to the Win32 api?

    Note: these issues are more with the provided libraries, not with the C# language itself. I think you’re asking for more capable libraries that fit better with the .Net model rather than interop libraries to the current unmanaged APIs.

    You may want to look into avalon to see if you like that model better.

  3. Nope, you can’t unload assemblies, see http://weblogs.asp.net/jasonz/archive/2004/05/31/145105.aspx. You can reset appdomain if you are lucky to run your code in a separate appdomain.

    I presonally prefer deterministic destruction as one available in MC++, AFAIK.

    As for Win32 API, why would I be writing in managed language then? If you look how ugly managed code looks when it relies on Win32 API call 99% of the time, you’d prefer native 🙂

  4. MIkhail: Doesn’t dispose given you your deterministic destruction? When you dispose, the resources are freed back to the system.

    Can you give me an example of how ugly it looks? Normally when I’ve p/invoked i’ve just passed structs and strings back and forth and it was fine.

  5. CM says:

    I agree with you about how having to explicitly initialize variables is a pain, but I think it can sometimes improve the readability of the code.

    For instance, in your example, if you only wanted to check if foo and bar are equal if they are both zero, wouldn’t it be better to state that in the conditional? What if foo and bar are both another value and the statement evaluates to true? I can imagine that determining what that problem was would be even more miserable than the one you mentioned above.

  6. drscroogemcduck says:

    I find the "using" syntax clumsy when working with multiple resources, and would prefer something like this:

    {

    dispose Brush b;

    dispose Brush c;



    }

    which would translate into:

    try

    {

    Brush b;

    Brush c;



    }

    finally

    {

    if (c != null) c.Dispose();

    if (b != null) b.Dispose();

    }

  7. Interesting: I guess I’ve never minded:

    using (Brush b = …)

    using (Brush c = …)

    {

    }

    it’s less characters than the dispose keyword 🙂

  8. CM: I did want the conditional to run any time they were equal, not just when they were equal and equal to 0.

    But I agree. Explicit initialization is fine, just as long as something checks and makes sure I do it!

  9. Methinks you need to try something like Valgrind ( http://valgrind.kde.org/ )

    Yeah, okay, it’s a GPL open source project associated with KDE and it’s only currently supported on Linux, but I’m being serious.

    The idea is that it runs an emulation of the X86 processor – much slower than reality, of course – but it [1] tracks each and every single bit (yes – bit level) of memory that a program uses and alerts you to any use of uninitialized values.

    ([1] Well, this is the traditional ‘memcheck’ skin, at any rate http://developer.kde.org/~sewardj/docs-2.0.0/mc_main.html – other skins can check other things.)

  10. Shannon: I’m aware of the grinned 🙂

    However, it has requirements that aren’t going to help here, namely glibc.

    I’m not looking for something that will catch the bugs at runtime, I’d rather have a compile time check that would at least warn you

  11. Uwe says:

    Never thougt about your

    using (Brush b = …)

    using (Brush c = …)

    {

    }

    I’ve always thought I have to write

    using (Brush b = x)

    {

    using (Brush c = y)

    {

    }

    }

  12. Does that alleviate the need for the new syntax you wanted?

  13. Jerry Pisk says:

    If you don’t like using unintialized variables just turn on warnings in your C++ compiler.

  14. Which warning tells you that your constructor has not initialized all the variables in the class?

  15. Lee Alexander says:

    Have a look pc-lint (http://www.gimpel.com/). It checks for uninitialised variables and out of order member assignments to mention just a few.

    Regards

    Lee

  16. Jerry Pisk says:

    You said you didn’t intialize a variable, not a class field. There’s a warning for variables but not for class fields.

  17. Jerry: I wrote: "Edit: I traced through it and it did indeed turn out to be an unintialized class field"

    🙂

  18. drscroogemcduck says:

    the

    using (…)

    using (…)

    {

    }

    construct is very nice… never thought about that 🙂