> So, C. How do you translate the errors across function calls? are you, or are your functions just returning 0/1? (at which point, you've lost much of the richness of exceptions, I think)

If you think your options are only "returning 0/1", you're not being creative enough.

For example COM has a 32-bit integer called HRESULT that all methods return. The high bit says something is an error. A few bits in the high 16 bits indicate where an error is from. The low 16-bits are private to whatever space is specified in the aforementioned bits. So if you take an error like 0x80070002 you can say it's an error, from the Win32 subsystem, and the error code is 0002 or file not found in this specific instance. Another component can set the high bits differently and end up with their own 16-bit error codes. I find when I write COM code the errors are much more meaningful than in a high-level language because it's all very explicit, you're constantly thinking about it at every function call, whereas in exception-based systems it's all just very haphazard and hand-wavy.

Or you could look at something like glib. Each method might have an out parameter which is a gerror object. This includes an error code and a string.

In other words there are several conventions out there. If you pick one and stick with it across a code base you can be very productive with a minimal amount of nonproductive "philosophical questions" like the ones in your post. Even if you have several libraries which have different conventions, you can adapt their conventions to the conventions of your code base and it's typically not a big deal.

> Instead of handling errors now at the source and handler, you'll also need to handle them at every intermediate point (if (f()) { free things; return ???; }),

Actually this "early return" pattern is quite bad in plain C, because if you have N allocations for example, each "return" statement needs to free between 0 and N buffers before leaving the function. That gets very maddening. One way to avoid this is to have only one "return" statement at the end of your function and free any loose buffers if-and-only-if they are non-null. This involves either constantly re-checking some error status, or using a goto to jump to the end of your function when something fails. IMO the 2nd is much cleaner. (Let that wrap around your high-level-language brain... but also know that any large C only code base is doing the same thing if they are sane; grep the Linux kernel for "goto" and you might start to get a picture... and while you're bashing C error handling and probably thinking ill for me for pulling out "goto", please keep in mind your "exception" concept is really just a goto that crosses stack frames...) In the end this pretty well simulates what you'd do in destructors in a C++ code base following the RAII pattern.

> and this burden makes exceptions wonderful.

In my experience it, on the contrary the exception concept just makes sure you have no idea that stuff can fail, and every small failure in a "shockingly" unexpected place blows up your entire program and terminates the process. Or you have Java's goofy "checked exceptions" concept and so lazy programmers will introduce do-nothing catch blocks to shut up the compiler.