Live data from Hacker News

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

250bpm.com

131–140 of 147 posts

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

#131

Earlier quoted context omitted.

My quick perusal of online links show that Objective-C is slower than C++, maybe due to its dynamic typing. It has the C compatibility and basic OOP. Yet, my idea was a language like this which is faster than C++. Maybe a statically typed version of Objective-C would do?

The OO parts of Objective-C will likely be slower than the OO parts of C++ in many cases. There are a few places where ObjC can help even the score on performance. Typically ObjC objects are not copied (cloned). Normal usage (within a collection, ivars, etc.) is with reference counting. Prior to C++11 (shared_ptr, unique_ptr, etc.), there wasn't a good way within the language itself to track object ownership without…

I appreciate the detailed reply. It seems like it's not a fit for my zero-overhead strategy but an interesting alternative to C++ for app development.

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

#132

Earlier quoted context omitted.

Currently, Go makes some decisions that hurt it for high performance systems, bare metal, and so on. Rust barely survived some beginner OS projects without its bloat and performance problems showing up. Once comparison I read showed Rust's compiler caught many bugs that slipped through Go's due to Rust design choices. I'm pulling for Rust in particular because its team made clever, design choices for their safety-vs-…

>Currently, Go makes some decisions that hurt it for high performance systems, bare metal, and so on. Can you expand on this? I have had no issue getting to C levels of performance by using "unsafe" or ASM a few small critical sections as needed (tight bodies of inner loops, etc or mmap based allocation).

Going from what people on different projects and forums said when I was Googling it. I could assess its current state better with a few questions. Can it run in kernel mode on bare metal? Can it run without a sizeable runtime? Are its core abstractions for common uses (arrays, strings, etc) at C++ performance at least? Are basic, demo algorithms small enough as object code to fit into a L1 cache?

These would be a nice start on assessing it as a true C++ alternative for varieties of systems programming. Come to think of it, I might also look to see if any C++ developers in high-end gaming have tried it. They're so tight on efficiency (and skilled at getting it) that might tell me plenty.

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

#133
post #38

Interesting article. So, more confirmation C++ is inferior for writing predictable or high performance applications. I actually see an opportunity for a C-compatible or C-competitive systems language here to beat C++ at its own game. Zero-cost abstractions plus solving C++'s specific problems, painless C FFI, and compilation to C (or LLVM) to leverage their compilers. Might make a nice combo. I doubt we'll see much t…

Is this a sort of informal RFQ? What's your budget?

There's no shortage of people taking a stab at language design and even resources to pull it off. The post was intended to provide a simple route for making (a) a better C++ or (b) a ZeroMQ variant with improved robustness & maintenance. Just inspiration and stuff to think about. If I had a budget, a few companies that can get the job done would already have the contract.

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

#134
post #102

Earlier quoted context omitted.

I disagree -- the determinant is about state management and locality of error handling and this is all about how your code is structured, not whether the error is expected or not in some nebulous sense. If you can handle the connect failure locally (i.e. probably no further away then caller of the connect function) then by all means do so. If you find another structure in your code makes other things simpler, but no…

Well, the reason exceptions should be reserved for exceptional cases is because they are gotos. There is no way around that, a function that both returns values and throws exceptions is more complex than one that doesn't because you are jumping through call frames. I once worked with a billing system that threw a BillingException when a charge didn't go through. It works ok, as long as your only response to such an e…

> separates exceptional situations from in-band normal error handling

Of course if you redefine "exceptional" to mean out of band error handling then we're in perfect agreement :)

I've also written billing systems and the worst possible thing that happens is that you get stuck on a single customer due to some unforeseen circumstances and can't go on to bill others. The ability to abort the in-code transaction for that customer and move on to the next is exactly what you want from the system, and the exception there makes that a far simpler thing to do (together with RAII for clean up).

> function that both returns values and throws exceptions is more complex

Indeed, but it doesn't really matter because the clean up you get from exceptions with RAII means that the correctness of the function is easier to reason about and that's what you really care about.

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

#135

Earlier quoted context omitted.

Several solutions. First I can think of: don't create situations where error can happen. Compile with exceptions turned off. Out of memory? Terminate the process/thread. Another: create your objects using some factory, make constructor empty and initialize class by said factory once instance is already created (perhaps recursively instantiating its members). This way all error generating code will be moved outside of…

Compiling with exceptions turned off is highly unusual. If you do that, you're not really writing C++ anymore, as it's a fundamental part of the language. Exceptions are the mechanism provided for indicating that it was impossible to construct an object, and to trigger appropriate cleanup actions.

> Compiling with exceptions turned off is highly unusual.

I thought it was routine. Until C++11 made smart pointers standard, it was unreasonably difficult to write exception-safe code, so my understanding was that a lot of C++03 code didn’t even try. Game developers would routinely use -fno-exceptions and -fno-rtti for reliability and performance reasons.

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

#136
post #127
post #120

Earlier quoted context omitted.

Well, "defect by design" is still a defect and I have to work around it on almost daily basis. Besides, being able to do (bool+int) could not come from C since C didn't have bool at the time. EDIT: actually, there are two defects here. One are the implicit numeric conversions. The other one, which causes me most grievance in this context, is that size() on containers returns an unsigned type.

> Besides, being able to do (bool+int) could not come from C since C didn't have bool at the time. Except that typedef int bool; /* or BOOL */ #define FALSE 0 #define TRUE (!(FALSE)) used to be quite common back then. So C++ only adopted an existing idiom in the C community.

Is there any production-level C code which relies on (int+bool, and other semantically meaningless arithmetic) working?

Besides, C++ broke nevertheless broke C compatibility because ++bool will never increment the value past 1, and bool=int will coerce int to 0 or 1. C will preserve the original values.

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

#137
post #120

Earlier quoted context omitted.

Well, "defect by design" is still a defect and I have to work around it on almost daily basis. Besides, being able to do (bool+int) could not come from C since C didn't have bool at the time. EDIT: actually, there are two defects here. One are the implicit numeric conversions. The other one, which causes me most grievance in this context, is that size() on containers returns an unsigned type.

I'm curious about that last bit. I occasionally hear this argument that size_t being unsigned is a bad thing. Presumably the standard library designers would claim that a size cannot be negative, so this is appropriate. Why, in your view, should that be a signed quantity?

Unsigned numbers in C++ are completely unsuitable for restricting the domain range because their "rank" (technical term) is higher than that of equally-sized signed types, which means that all operands are promoted to unsigned if one operand is unsigned. Of course, the result is unsigned too.

Now, you often want to do arithmetic with numbers, right? You could think that, given two containers with c1.size() Because of default promotion rules and size() returning an unsigned number, (signed) 1 is converted to an unsigned number and the whole expression is evaluated in modulo arithmetic.

Now, if c1 is empty (c1.size() == 0), then subtracting 1 from 0 in unsigned arithmetic wraps around (this is how unsigned arithmetic is defined) to a huge number (4 billion on 32 bit machines). The simple comparison above will fail in THE singular case of having an empty container on left hand side.

You also lose any possibility of detecting errors. (E.g., if size() were signed and could return a negative number, you could effectively assert on that. If assert triggered, then something really bad happened -- maybe two concurrent threads modifying the data structure w/o proper synchronization.)

I personally think it makes reasoning about a program harder; the above comparison was just the most trivial example. unsignedsigned comparisons also trigger a bunch of warnings, because I use signed numbers for everything else, so the code ends up having a bunch of unnecessary casts. (I do not want to disable the warning because genuine mishaps of mixing signed/unsigned do happen.)

I believe the consensus is (also Stroustrup's recommendation) is that unsigned should be used as "give me modulo arithmetic" instead of "this number cannot be negative".

So, IMHO, unsigned size() was a mistake and is a big PITA when you try to develop robust software and creates less maintainable code (e.g. in the above simple example, you'd have to special-case the c1.empty() case with if). Casting size() to signed type immediately if I'm going to do anything else than iterate over the container is the least evil for me.

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

#138
post #136
post #127

Earlier quoted context omitted.

> Besides, being able to do (bool+int) could not come from C since C didn't have bool at the time. Except that typedef int bool; /* or BOOL */ #define FALSE 0 #define TRUE (!(FALSE)) used to be quite common back then. So C++ only adopted an existing idiom in the C community.

Is there any production-level C code which relies on (int+bool, and other semantically meaningless arithmetic) working? Besides, C++ broke nevertheless broke C compatibility because ++bool will never increment the value past 1, and bool=int will coerce int to 0 or 1. C will preserve the original values.

> Is there any production-level C code which relies on (int+bool, and other semantically meaningless arithmetic) working?

Yes. I have seen enterprise code making interesting tricks to covert handle values into pointers, back in the late 90's.

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

#139
post #138
post #136

Earlier quoted context omitted.

Is there any production-level C code which relies on (int+bool, and other semantically meaningless arithmetic) working? Besides, C++ broke nevertheless broke C compatibility because ++bool will never increment the value past 1, and bool=int will coerce int to 0 or 1. C will preserve the original values.

> Is there any production-level C code which relies on (int+bool, and other semantically meaningless arithmetic) working? Yes. I have seen enterprise code making interesting tricks to covert handle values into pointers, back in the late 90's.

Code that switches over a variable nominally declared to be of type BOOL and handles more than 2 distinct value cases is always such a joy to read; every enterprise grade code base should have at least one of these for entertainment purposes.

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

#140
post #119

Earlier quoted context omitted.

I don't always write dangerous code, but when I do I fully realize it =). And it has nothing to do with any of the features that you listed. In fact "threading" in C++ is safer because of the availability of high-quality libraries providing task-based parallelism such as TBB, move semantics is used all the time in C albeit manually with pointer manipulation. It is true that not all of the features play well together,…

> In fact "threading" in C++ is safer because of the availability of high-quality libraries providing task-based parallelism such as TBB, move semantics is used all the time in C albeit manually with pointer manipulation. It is true that not all of the features play well together, but it's nothing compared to the C pitfalls that I mentioned. Well, if I use libraries to avoid C's pitfalls, that language will be safe,…

The number of copy/move constructors is zero, by the way, it's not hard (well, could be one if you're using 1980s compilers)
Post reply on HN