Live data from Hacker News

Why should I have written ZeroMQ in C, not C++ (2012)

250bpm.com

81–90 of 170 posts

Re: Why should I have written ZeroMQ in C, not C++ (2012)

#81
post #12

This article is simultaneously both obsolete and completely current. Obsolete in that the C++ committee has addressed almost all of the issues raised (e.g. constructor semantics, xception semantics et al) though the discussion of site-of-error/handling-of-error continues unabated. Later versions of C++ (17and 20) are powerful and expressive systems programming languages that aren’t like the object-oriented messes of…

True, I recently returned to C++ after many years absence and I'm thrilled with all the good stuff that has been added BUT it took me quite a while to learn how I'm going to unlearn/relearn my old practices.

I decided to treat it as if it was a language I had never seen before. That helped a lot.

Re: Why should I have written ZeroMQ in C, not C++ (2012)

#82

Earlier quoted context omitted.

> You don't get to access the return value unless you deal with handling the error first. Well, that's exactly what I was referring to. 80% of the time you don't / can't know what to do with the error at a given call site, so from what I could see, either people end up doing nothing and "abandoning" the error (bad) or panicking (worse). It's better to just let the error go transparently so that if someone actually ca…

Hm, we must read very different Rust code. ? is even easier than a panic. And that search has a ton of false positives: both in general, as well as "unwrap" being the more common way to get a Result to panic.

c'mon...

    $ cd servo/components
    $ rg -F 'panic!' | wc -l
276

Likely a fair amount is justifiable, but things like this ? https://github.com/servo/servo/blob/master/components/script... or this https://github.com/servo/servo/blob/master/components/gfx/pl... ?

that's a really strong code smell (or at least doing a similar thing in a C++ program, e.g. calling abort() / SIGTRAP, would be, even with a signal handler, a really really really long discussion in code review)

Re: Why should I have written ZeroMQ in C, not C++ (2012)

#83
post #50

Writing in C++ means that the C++ library you are using becomes a dependency. Probably not an issue, if you have the source code to all libraries that you use, but maybe an issue if you are vendor and try to support not only all possible modern compilers, but what they target to (platforms, runtimes, models, etc.) With just "C", not "C" only at the interface part, you can avoid that. Even to the point that your binar…

Not sure why this got downvoted? Anyone to comment? I use C++ daily on my job, and I'm very happy with its developments - especially C++11, C++14, C++17 and what's coming in C++20 - but statically linking problems are real, and pain to solve (long term). We do mostly MSVC, where some teams are still in VS2017, others VS2019 - and while they are compatible - the compatibility works only if your final app is compiled with the latest compiler from each version, which puts our team (doing mostly libraries, and providing precompiled ones) that we should use the lowest version, but then our CI infrastructure might use even earlier.

With "C" there is less to care there, as most is set in stone (unless you use some really compiler vendor specific extensions, that appear during link time).

Just an example - https://devblogs.microsoft.com/cppblog/making-cpp-exception-... - this is great improvement, but also means that if you've compiled your lib with VS2019, and it throws an exception under application that uses VS017 - it'll not work.

Re: Why should I have written ZeroMQ in C, not C++ (2012)

#84

I think there's a lot of merit to this post, but it really shows its age. Modern C++ typically suffers from only the last point raised - exceptions during destruction, but that goes against the all good C++ practices. Overall, the author's approach to exception use is flawed. It's bad form to use exceptions for code flow purposes, as per their example. If you throw an exception in the same block that catches the exce…

> I've never come across a situation where exceptions during destruction is a problem, but am very interested in any examples. C++ standards define that you _can_ throw exceptions, but you shouldn't for the exact reason raised in the article - the process will be terminated as there's nothing else that can be done. If there aren't any destructors containing the throw keyword, it's not likely to throw an exception - OOM or other system exceptions are still possible, but why are you allocating memory in a destructor? destructors just need to release resources and clear down the object, it shouldn't be requesting more resources. Thinking about saving the object state before exit? wrong place to do it.

std::ofstream is a good example. Flushing and closing the file happens in the destructor if not done explicitly. Not being able to throw IO exceptions from the destructor breaks object encapsulation by requiring explicit error-checking. One could argue that it's simply a bad abstraction; an open file handle is not in a fully consistent state and so a C++ object pretending to be valid while representing a file handle may have been a poor choice as opposed to e.g. record-based or transactional IO where writes could be atomically flushed or fail.

In general any objects representing IO can be victims of error conditions in destructors because external state can change unexpectedly between the last valid state of the C++ object and its destruction, especially if the object abstracts away some non-deterministic behavior.

Destructing objects may also require modification of other data structures: Updating special containers or indexes, unregistering from a queue, waiting for thread completion, etc. This can force destructors to eat exceptions that should otherwise be passed up to callers.

Re: Why should I have written ZeroMQ in C, not C++ (2012)

#85
post #22

1. That "C equivalent" for error handling is not an equivalent at all. If one could handle the error in the same function then there is no reason to throw. The "C equivalent" is returning an error code, which has other problems. 2. One can handle errors in initialization without exceptions and half-initialized objects: Make your constructor private and expose a static member function that returns an optional (where T…

Completely agree. I was about to write something along these lines but you did a great job. :-)

In a decade using C++, I haven't encountered these problems. I never use exceptions and I do exactly what you suggested in #2: if construction can fail, have a factory method and a private constructor (I use a simple ValueOrError type, rather than optional, to be able to communicate information about the error, though: https://github.com/alefore/edge/blob/876c4328610262b11fda553...).

Cheers!

Re: Why should I have written ZeroMQ in C, not C++ (2012)

#86
I don't get it. Exceptions are bad -> don't use exceptions. Constructors can fail with exceptions -> use a factory pattern and handle errors explicitly. Destructors can't fail: right, so don't, and yes, if you need to do finalization that could fail then that has to be explicit (as in C) and you can handle errors there, and yes, that leaves you with half-destructed objects, but so what.

No, I think high-level static data typing is very important. Today Rust would be a better language than C++ for this, but C++ is still better than C.

Re: Why should I have written ZeroMQ in C, not C++ (2012)

#87

Earlier quoted context omitted.

Hm, we must read very different Rust code. ? is even easier than a panic. And that search has a ton of false positives: both in general, as well as "unwrap" being the more common way to get a Result to panic.

c'mon... $ cd servo/components $ rg -F 'panic!' | wc -l 276 Likely a fair amount is justifiable, but things like this ? https://github.com/servo/servo/blob/master/components/script... or this https://github.com/servo/servo/blob/master/components/gfx/pl... ? that's a really strong code smell (or at least doing a similar thing in a C++ program, e.g. calling abort() / SIGTRAP, would be, even with a signal handler, a rea…

loc in that same directory says 289958 lines of Rust code, that is a ratio of 0.00095186199. That is pretty small. 175 unwraps, which I am actually shocked is smaller than panics.

And yes, I do think that both of these are pretty justifiable: both of these are effectively assertions, which is not unheard of in C either.

Re: Why should I have written ZeroMQ in C, not C++ (2012)

#88
post #6

It seems like the author's main complaints are avoided if one follows the Google C++ style guide, which says: - Don't use C++ exceptions - Don't do work in constructors (prefer "Init" or factory functions instead) https://google.github.io/styleguide/cppguide.html There may be other reasons to prefer C over C++, but if you don't like exceptions, you don't have to use them.

> Don't use C++ exceptions That's not what Google's C++ style guide says at all. They only argue that Google's old C++ code base is not exception-tolerant, thus as they don't want to waste time and they don't want risk adding bugs by refactoring their legacy code then they just decided to not use exceptions. That's it.

You're right. My point wasn't that one should blindly follow Google's style guide and avoid using C++ exceptions, only that there is an alternative to the C/C++ dichotomy that the author presents. It's possible to write millions of lines of C++ without using exceptions. There's a trade-off, which is described in more detail in the style guide, and the choice depends on the specifics of one's project.

Re: Why should I have written ZeroMQ in C, not C++ (2012)

#89

I think there's a lot of merit to this post, but it really shows its age. Modern C++ typically suffers from only the last point raised - exceptions during destruction, but that goes against the all good C++ practices. Overall, the author's approach to exception use is flawed. It's bad form to use exceptions for code flow purposes, as per their example. If you throw an exception in the same block that catches the exce…

Another way to support RAII without throwing exceptions is to somehow make the error case an explicit configuration of the class with well-defined behavior. For example, in a "File" class with no filedescriptor you could return a defined "error" from any function calls which would require a filedescriptor. Receiving such a return value or return structure would then signal that the File class is not in a working stat…

I think that's something called 'the Maybe pattern (a monad)'.

Re: Why should I have written ZeroMQ in C, not C++ (2012)

#90

Earlier quoted context omitted.

My understanding: Pick zmq if you want something safe and battle-tested with good client library support. Pick nng if you want to be at the forefront of new tech or need some of its unique features over zmq ( https://nanomsg.org/documentation-zeromq.html ). Performance-wise nng still seems like it's inferior to zmq because it's not as heavily optimized. There are lots of performance-related unresolved Github issues.…

nanomsg was abandoned? I know the previous maintainer moved on to nng, but no one is maintaining it now?

I don't know. Maybe it's not abandoned and maintained by someone. I was using the word loosely as in "focus has moved to nng" and it makes little sense to use nanomsg for a new project at this point.

In my experience, if the core contributor moves on and it's not a company, it's only a matter of time before it's fully abandoned. Better to get away from it soon ;)

Post reply on HN