For C programmers that hate C++ (2011)
thanassis.space
thanassis.space
I find a number of developers reach for C++ because they aren’t comfortable with C or low-level development. For instance, will copy memory into a std::vector or std::string just to use the STLs search functions where a simple finite state machine would be more appropriate. I also find a correlation between C developers having a better understanding of things like file descriptors, poll/select/epoll for an event loop, while a C++ developer is more likely to use std::thread and then have to deal with proper locking.
Working in a constrained environment, I like C exactly because it “does less”. It’s more explicit, simpler, hides less behind abstractions in practice.
The STL was specifically designed so that pointers are iterators and you are able to pass a pair of pointers to pretty much any STL algorithm. This you should never need to copy memory into a container such a vector or string to be able to use the STL algorithms.
I can't say the same about C++, which feels as if one has to set clear and definite limits, banning most of the language, before one can deploy it in a sane manner.
C just has data structures and functions (small surface area). Its simplicity makes it much easier to read.
Some languages prioritize adding features and power. C++, Rust, and Swift are examples.
Other languages prioritize minimizing the surface area. C, Go and Scheme are examples.
Programmers either value minimal surface area (better for reading) or maximal features and power (better for writing) and are more likely to adopt languages based on this classification.
For example, C programmers are more likely to adopt Go over C++ and Rust. And, C++ programmers are more likely to adopt Rust.
This is not even REMOTELY true. Plenty of companies use massive pure C++ projects.
C++ classes are really just syntactic sugar for data organization. You can do the same type of organization in C, things just have to be more explicit. The benefit if using C is that you can use constructs where needed while trimming fat where its not.
Here's what he wrote in order to complain about it:
if (mode == ambient) {
// handle pixels as ambient...
int steps = right.a.x - left.a.x;
float dv = (right.a.ambientLight - left.a.ambientLight)/steps;
float currentIntensity = left.a.ambientLight;
for (i=left.a.x; i<right.a.x; i++) {
WorkOnPixelAmbient(i, dv);
currentIntensity+=dv;
}
} else if (mode == gouraud) {
// handle pixels as gouraud...
int steps = right.g.x - left.a.x;
float dred = (right.g.red - left.g.red)/steps;
float dgreen = (right.g.green - left.g.green)/steps;
float dblue = (right.g.blue - left.g.blue)/steps;
float currentRed = left.g.red;
float currentGreen = left.g.green;
float currentBlue = left.g.blue;
for (j=left.g.x; i<right.g.x; j++) {
WorkOnPixelGouraud(j, currentRed, currentBlue, currentGreen);
currentRed+=dred;
currentGreen+=dgreen;
currentBlue+=dblue;
}
Nobody should do that. We use a temporary variable of the correct type. For example this way (but it could also be done with pointers to access directly the union variable): switch(mode) {
case AMBIENT: {
PixelDataAmbient l = left.a;
PixelDataAmbient r = right.a;
int steps = r.x - l.x;
float dv = (r.ambientLight - l.ambientLight)/steps;
/* ... */
break;
}
case GOURAUD: {
PixelDataGouraud l = left.g;
PixelDataGouraud r = right.g;
int steps = r.x - l.x;
/* ... */
break;
}
/* ... */
default:
show_error("Illegal mode");
}
There is no need to cart all the .a. and .g. around and clutter the code. And there is no possibility to accidentally access the wrong fields the wrong way: trying to access l.ambientLight in the second block (GOURAUD) will fail at compilation since a PixelDataGouraud doesn't have an ambientLight field. It is also not possible to do PixelDataGouraud l = left.a; since left.a is not a PixelDataGouraud.Much cleaner, much more readable and avoids most of the possible errors he complains about.
You can also have internal workings with static functions/variables that you can use as helpers, but invisible to outside code and not declared in header files.