4 ms·
Don't fight the language (and this goes for any language). If you fight the language (go against the idioms of the language), you're going to end up unhappy wit
by deathanatos 13y ago
Don't fight the language (and this goes for any language). If you fight the language (go against the idioms of the language), you're going to end up unhappy with it. In my opinion, he's fighting the language. Additionally, while he rants at C++ for some of its behavior, he doesn't really address what he'd do in C. Also, he seems to not understand what "undefined behavior" is. Last, RAII is your friend in C++, and IMHO, is the difference between programming in "C with some extra stuff, but mostly more verbose" and C++.
Exceptions:
> The decoupling between raising of the exception and handling it, that makes avoiding failures so easy in C++, makes it virtually impossible to guarantee that the program never runs info undefined behaviour.
The example is basically that when you call a function, it could raise any error, so we don't know which to catch. This problem exists in most languages where errors can occur (I've had to deal with this a lot in Python). 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) 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 ???; }), and this burden makes exceptions wonderful.
> Consider what happens when initialisation of an object can fail. Constructors have no return values, so failure can be reported only by throwing an exception.
Raise an exception, except… (no pun intended)
> However, I've decided not to use exceptions.
(You're fighting the language.) Is this just a complaint that maintaining exception safety in ctors is difficult? unique_ptr and shared_ptr (and RAII) make it fairly straight-forward and easy, and often a ctor can be completely exception safe without try/catch. (If releasing the partially constructed state is the issue, it's hard to tell.)
> if termination can fail, you need two separate functions to handle it
Yes, you will. Honestly, this never sat well with me, but I think it makes good sense. But his example seems to imply you can fold them into one function in C, which you simply can't (under the same assumptions that the C++ code was held to). If "termination" can fail, you'll still need thing_terminate() and thing_deallocate(), or you'll never be able to deallocate the thing; or you're assuming that the C thing_terminate() will just report the error and deallocate anyways. The larger C++ problem remains in C, and the author doesn't touch on it: if you're (manually, in C) unwinding the stack due to error, and you need to release a thing in the process, and that release fails: what do you do? C++ gives you two options, in my opinion: either you ignore it/log it, by not throwing in a dtor, or (and people don't like this one) you throw in the dtor and risk there being two exceptions. C++'s response will be to terminate the program. In C — or any language — what would you do with two errors?
- malkia 13y ago> Additionally, while he rants at C++ for some of its behavior, he doesn't really address what he'd do in C. He already started working on "C" re-implementation of ZeroMQ with different API and zeromq wrapper on top of it (so it could be used as zeromq replacement). https://github.com/250bpm/nanomsg https://github.com/250bpm/nanomsg
- asveikau 13y ago> 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.