foo (a, b, c)
char *a;
int b, c;
{
/* do something cool here */
}
And there were no "function declarations" (who needs argument type and cardinality checking anyway), no "slash slash" single line comments, no need to declare a return type as int was implied, say goodbye to const and volatile qualifiers, any char array is mutable (including those defined in double quotes), plus be sure to use function pointers thusly: (*some_pointer) (insert, args, here);
Instead of: some_pointer (looks, like, a, function);
Oh yeah, and say adios to struct initialization using the C89 syntax. And it's a no-no to try and initialize a local array along the lines of: char *strings = {
"this", "is", "convenient", "isn't", "it?"
};
So if you wish to assert (pun intended) "that plain-old C really is better", then be sure to acknowledge where a non-trivial amount of what is known as "plain-old C" stems from.C is so tedious to write that even if I didn't have access to C++ I would try something else first when the need to write cross-platform/performant code would come.
The point is: it's not appropriate to evangelise C (or any other language) without pointing out some of its major disadvantages. This is simply spreading misinformation.
This becomes much simpler once you learn how to write your own variadic functions (it's not that hard, though I do admit it could be prettier). Then you just write one single logerrf function or whatever, which 9 times out of 10 you can carry with minor modifications to your next project. Java does try/catch better in the sense that with checked exceptions you can force library users to at least acknowledge exceptions. Without checked exceptions, try/catch just hides the extra int *err argument under the rug, actually increasing the risk of library users not acknowledging edge cases.
>and resource management
I don't like C++ malloc'ing things behind my back. I see it as trading maintainability for instant gratification. The problem is compounded by the way C++ doesn't play nice with gdb/valgrind. Memory leaks and other memory errors are much easier to fix in C than C++.
>C is so tedious
It really isn't, though, if you use it right. Whatever syntactic tedium it has is more than compensated for by the lightning-fast compile time and the infinitely simpler compiler errors (due to no overloading, no templates...)
I agree and I want to add that for a language "with a bias towards system programming" C++ makes strange assumptions about the memory. It assumes that there is only one kind of memory available for every operation (and it does its thing with that by default). Then it goes and further assumes that there is only one way (no finer further details whatsoever) of getting that one and only type memory. It's exactly the one boot fits all kind of thinking that Mr. Stroustrup suggests that C++ hasn't.
The "object-orientedness" of C++ really boils down to implicitly passing the this pointer to member functions, inheritance + virtual functions, and namespaces. All of these can be emulated in what I would call "C with discipline". Just be consistent in your naming conventions, always use a common prefix for globally visible functions and types, and use structs of function pointers whenever you really need virtual functions.
And, before you mention it, use clang to avoid getting the page long templates related errors.
Type-generic data containers can still be implemented with void pointers and very little runtime overhead, for example: http://lxr.nginx.org/source/src/core/ngx_array.h
I am working in DSP project which was started with typical C++ OO BS, finally with ended up with C compiled as C++ + some simple templates for cases as above.
#define MAX(a,b) ({ \
typeof (a) _a = (a); \
typeof (b) _b = (b); \
_a > _b ? _a : _b; \
})
The inability to write template functions can be compensated by designing your function so that it takes a function pointer where the type-specific action occurs. auto max = [](auto a, auto b) {
return (a > b) ? a : b;
};
max (3.1415, 42); // returns double
max (42ul, 78u); // returns unsigned long
max (17, 16); // returns intHow is it template 'nonsense', when those templates do exactly that?
int maxi(int, int);
double: maxd(double, double);
...
#define max(x) _Generic((x), int: maxi, double: maxd, ...default: maxi)