Comparing Exceptions to Goto

Joel (of www.joelonsoftware.com) says exceptions are bad, because they're unclear and because they change program flow in ways you don't expect.

But unexpected errors change program flow in ways you don't expect, too!  Exceptions can be thrown by software because it's not happy, or they can be thrown by the OS because you've done something terrible (like access memory you don't own).

His current example says:

void InstallSoftware(int a, int b)
{
    CopyFiles(a);
    UpdateRegistry(b);
}

Would be a mistake with exceptions, because if UpdateRegistry threw an exception then the job would be incomplete (files might be copied but the registry would be in an inconsistent state). 

Which is absolutely true, and would also be true if UpdateRegistry() dereferenced a bad pointer or blew up in some other way in his example which does traditional error handling.  Exceptions allow you to catch things going wrong and deal with them in a controlled manner.

bool InstallSoftware(int a, int b)
{
    bool filesCopied = false;
    bool success = false;

    try
    {
        CopyFiles(a);
        UpdateRegistry(b);
        success = true;
    } catch (...)
    {
        UnCopyFiles();
        UnUpdateRegistry();
    }

    return success;
}

The difference here is that if anything goes wrong anywhere during the copying process, you'll be rolling back any potential changes.  The alternative code:

void InstallSoftware(int a, int b)
{
    if (CopyFiles(a))
        if (!UpdateRegistry(b))
            UnCopyFiles();
}

Wouldn't.

Using exceptions doesn't mean you don't have to handle errors.  It gives you control over where and how you handle errors.

Comparing Exceptions to goto is incorrect.  Look at this code:

void UnknownFailure()
{
    MyObjOne bargle;

    try
    {
        for (int i=0; i<10; i++)
        {
            MyObjTwo orgle(bargle);
            orgle.Something(i);
         }
    } catch (...)
    {
         // Something bad happened
    }
}

If orgle.Something throws an exception or anything else bad happens inside the for loop, MyObj will be destroyed as the stack is unrolled.  If the exception takes you out of the current function and up a couple of levels, that's fine - everything is being cleaned up as the stack is unrolled.  That's the difference using something like setjmp/longjmp and exceptions.

You can implement exceptions badly; and I agree that not using exceptions is better than implementing exceptions badly.. but exceptions implemented correctly and consistently in an application is much better than traditional error handling.