Is there any real reason to use "const"?

H. S. Teoh hsteoh at quickfur.ath.cx
Mon Jan 24 18:48:48 UTC 2022


On Mon, Jan 24, 2022 at 05:38:45PM +0000, rempas via Digitalmars-d wrote:
> On Monday, 24 January 2022 at 17:30:26 UTC, Ali Çehreli wrote:
> > Yeah, that thought disappears once one realizes that humans are
> > mistake-making machines. :)
> > 
> 
> Yeah, really working towards accepting that but I'm getting closer and
> closer each day...

I used to be a hardcore C programmer. So hardcore that I won an award in
the IOCCC once (well OK, that's not something to be proud of :-D).
Correctly answered a C question on an interview technical exam that even
my interviewer got wrong.  Was totally into the philosophy of "the
programmer knows better, compiler please step aside and stop trying to
restrict me". Believed my code was perfect, and could not possibly have
any bugs because I mulled over every line and polished every character.
Didn't believe in test suites because I hand-tested every function when
I wrote it so there can't have been any bugs left. And besides, test
suites are too cumbersome to use.  Used to pride myself on my programs
never crashing. (And the times they did I blamed on incidental factors,
like I was too distracted because some idiot was WRONG on the internet,
gosh the injustice!)

Then I discovered D. And in particular, D's unittest blocks. Was very
resistant at first (why would I need to test perfect code), but they
were just so darned convenient (unlike unittest frameworks in other
languages) they just keep staring at me with puppy eyes until I felt so
ashamed for not using them. Then the unittests started catching bugs.
COPIOUS bugs. All kinds of boundary cases, careless typos, logic flaws,
etc., in my "perfect" code.  And EVERY SINGLE TIME I modified a
function, another unittest started failing on a previously-tested case
(that I disregarded as having nothing to do with my change so not worthy
of retesting).

Then this awful realization started dawning on me... my code was NOT
perfect. In fact, it was anything BUT perfect. My "perfect" logic that
flowed from my "perfect" envisioning of the perfect algorithm was
actually full of flaws, logic errors, boundary cases I hadn't thought
of, typos, and just plain ole stupid mistakes. And worst of all, *I* was
the one making these careless mistakes, practically EVERY SINGLE TIME I
wrote any code.  What I thought was perfect code was in fact riddled
with hidden bugs in almost every line.  Usually in lines that I'd
written tens of thousands of times throughout my career, that I thought
I could write them perfectly even in my dreams, I knew them so well.
But it was precisely because of my confidence that these "trivial" lines
of code were correct, that I neglected to scrutinize them, and bugs
invariably crept in.

Then I observed top C coders in my company make these very same
mistakes, OVER AND OVER AGAIN. These were not inexperienced C greenhorns
who didn't know what they were doing; these were top C hackers who have
been at it for many decades. Yet they were repeating the same age-old
mistakes over and over again. I began to realize that these were not
merely newbie mistakes that would go away with experience and expertise.
These mistakes keep getting made because HUMANS MAKE MISTAKES. And
because C's philosophy is to trust the programmer, these mistakes slip
into the code unchecked, causing one disaster after another. Buffer
overflow here, security exploit there, careless typos that cause the
customer's production server to blow up at a critical time. Memory leaks
and file descriptor leaks that brought a top-of-the-line server to its
knees after months of running "perfectly".  And the time and money spent
in finding and fixing these bugs were adding up to a huge mountain of
technical debt.

Today, my "trust the programmer" philosophy has been shattered. I *want*
the compiler to tell me when I'm doing something that looks suspiciously
like a mistake. I *want* the language to be safe by default, and I have
to go out of my way to commit a mistake. I want the compiler to stop me
from doing stupid things that I'd done a hundred times before but
continue to do it BECAUSE HUMANS ARE FALLIBLE.

Of course, I don't want to write in a straitjacket like Java makes you
do -- there has to be an escape hatch for when I *do* know what I'm
doing. But the *default* should be the compiler stopping me from doing
stupid things.  If I really meant to cast that pointer, I *want* to have
to write a verbose, ugly-looking "cast(NewType*) ptr" instead of just
having a void* implicitly convert to whatever pointer type I happen to
have on hand -- writing out this verbose construct this forces me to
stop and think twice about what I'm doing, and hopefully catch any wrong
assumptions before it slips into the code.  I *want* the compiler to
tell me "hey, you said that data was const, and now you're trying to
modify it!", which would cause me to remember "oh yeah, I *did* decide 2
months ago that this data should not be changed, and that other piece of
code in this other module is relying on this -- why am I trying to
modify it now?!".

As Walter often says, programming by convention doesn't work. Decades of
catastrophic failures in C code have more than proven this. Humans are
fallible, and cannot be relied on for program correctness. We're good at
certain things -- leaps of intuition and clever out-of-the-box solutions
for hard problems.  But for other things, like keeping bugs out of our
code, we need help. We need things to be statically verifiable by the
compiler to prove that our assumptions indeed hold (and that somebody --
namely ourselves 3 months after writing that code -- didn't violate this
assumption and introduce a bug during a last-minute code change before
the last release deadline).  Weak sauce like C++'s const that can freely
be cast away with no consequences anytime you feel like it, will not do.
You *need* something strong like D's const to keep the human error in
check. Something that the compiler can automatically check and provide
real guarantees for.


T

-- 
Bare foot: (n.) A device for locating thumb tacks on the floor.


More information about the Digitalmars-d mailing list