[OT] C vs C++

H. S. Teoh hsteoh at qfbox.info
Thu Sep 8 22:26:12 UTC 2022


On Thu, Sep 08, 2022 at 09:15:27PM +0000, Dukc via Digitalmars-d wrote:
[...]
> Going crazy with macros will certainly make C as hard to read as any
> C++.  But I think there may be a point in this otherwise. In C one
> pretty much only has to avoid being clever with the preprocessor, and
> it's hard to totally mess up the readability.

Are you ... *sure*? :-P

Haha, wait till you see some of the C code I've had to deal with.
Somebody, in a glorious fit of NIH, had decided that it was a good idea
to reinvent C++'s OO -- except partially, inconsistently, and without
the syntax niceties and compiler guarantees -- by writing function
pointers everywhere. And I mean, literally *everywhere*: open up a page
of code the code, and almost every line involves at least 1 call to a
function pointer. Most lines contain at least 2-3, some really bad ones
have 6 or more.  Basically, it's trying to imitate C++ polymorphic code
except in C.  But the problem is, since this is all hand-made and not
supported nor enforced by the compiler, the correspondence between
function pointers and logical virtual method calls is not 1-to-1...
meaning that sometimes you *think* a certain funcptr call would go
somewhere, but it goes somewhere else instead, because somebody along
the line decided to "override" it (unofficially) in order to, I don't
know, fix a bug or something.

And being all hand-spun, it's anybody's guess where these funcptrs are
initialized. You don't have syntactic ctors and class definitions that
you can look up to find out; these are all squirrelled away in obscure
parts of the code that, themselves, are chockful of funcptrs leading who
knows where.  Suspect a bug on some particular line of code?  Good luck
figuring out where that funcptr actually leads...  Well, you say, that's
easy, just find out where it's initialized.  OK, so you try to figure
out where it's initialized (hint: it's not anywhere you might imagine,
you have to search long and hard for it).  After you locate the code
that initializes it (by which time you're already tearing out your hair
in frustration), you see that it's also riddled with funcptr calls
head-to-toe, and exactly which value it uses to initialize the original
funcptr is dependent on a whole bunch of other funcptrs that leads who
knows where.  So, to figure out where 1 funcptr leads to, you have to
decipher 15 others.  And each of them, in turn, requires deciphering
where another 15 lead to (because their respective initialization
functions, you see, are written in exactly the same way).

So you can stare at the original function until the cows come home, and
you'd have no idea what it actually does.  Forget about reading the
code; the only way to figure this out is to use a debugger and
breakpoint it, then inspect where the funcptrs actually point to at
runtime.  Trying to decipher the initialization code is like getting
caught in a shark loan: you start out with a debt of 1 funcptr, and you
end up owing another 15, and for each of the 15, you owe yet another 15.
Compound funcptr interest FTW.

Yep, definitely hard to totally mess up readability in C. :-P


> But in C++ there are so much complex features that the code can have
> much worse readability issues than those caused by typical C problems
> (poor naming, no comments, lots of global state, oversized functions).

These are by far not the only problems with C. :-D  (See above. :-P)


[...]
> Maybe the conclusion is that C++ is virtually always better than C in
> itself, but it's use is teached so badly that it often ends up worse.

Um, no.  SFINAE + Koenig lookup.  That combo alone will give you
migraines for weeks, if not months.  No amount of good/bad teaching will
negate the fact that this combo is the stuff of nightmares.  Add to it
mix all the other "niceties" of C++, and ... yeah. Not going there.  I
think I'm suffering from C++ PTSD.

At least in C, once you nailed down that darned funcptr, you *know* it
isn't gonna cheat on you and go on a tryst with a completely unrelated
module that you hadn't suspected was surreptitiously #include'd where
the same identifier was gratuitously reused just to spice up your life.
Identifier hijacking FTW!


[...]
> Since D is a fairly complex language, I think we should talk more
> about when we should avoid the most complex features, such as traits.

One of the things I love about D is: the easier it is to write something
and the simpler it looks, the higher the chances are that it's actually
correct.  (Contrast this with C++, where the simplest way to write
something is almost certainly the wrong way; the right way involves
arcane incantations of black magic that not even seasoned C++ coders
have come to an agreement of which way is actually correct. And the
resulting code reads very much like an undecipherable arcane inscription
reverse-encrypted in Klingon.)

So I'd say the rule of thumb in D is, write it in the simplest way
possible to achieve what you want. If that fails, then consider the next
more complex thing up the ladder of complexity.  Only reach for the
ultimate weapon (did I hear, string mixin? ;-)) when no other recourse
suffices.


> I suspect typical D programmers are not burned by overengineered
> language features as much as C programmers. Don't get me wrong, traits
> are great, but they do have a complexity cost in readability and error
> message quality. Sometimes a less perfect but simpler feature is the
> better choice even in D.
[...]

Agreed.


T

-- 
"A man's wife has more power over him than the state has." -- Ralph Emerson


More information about the Digitalmars-d mailing list