
The cost of forsaking C - zik
https://blog.bradfieldcs.com/the-cost-of-forsaking-c-113986438784
======
sreque
Knowing C has made me a better and much more versatile programmer than I would
be without it. For instance, a while back I had to diagnose a JVM core dumping
sporadically, and I was able to use my knowledge of C to try to recover valid
return addresses from a corrupted stack, figure out there was a signal handler
block on the stack, then further unwind from there to find out the whole story
of what likely caused the crash.

Knowing C also helps me write more performant code. Fast Java code ends up
looking like C code written in Java. For instance, netty 4 implemented their
own custom memory allocator to avoid heap pressure. Cassandra also has their
own manual memory pools to try to improve performance, and VoltDB ended up
implementing much of their database in C++. I've been able to speed up
significant chunks of Java code by putting my "C" hat on.

I would recommend every college student learn C, and learn it from the
perspective of an "abstract machine" language, how your C code will interact
with the OS and underlying hardware, and what assembly a compiler may
generate. I would consider learning C for pedagogical purposes to be much more
important than C++.

~~~
kovrik
Can it be replaced with Rust nowadays? Is it low-level enough? Or borrow
checker and lifetimes defeat the whole purpose?

~~~
sreque
For teaching purposes in a university I don't know if rust would be better or
not. Keep in mind that the goal isn't necessarily to learn C the language;
it's to learn enough of the core language to explore things like:

* How the code is executed on modern hardware and operating systems.

* How various language features might be compiled to assembly

* Memory layouts for things like stack frames, how a simple heap allocator might work, array layouts, layouts for other structures like linked lists, etc.

* The relative cost of various operations and how to write code that is cache friendly.

* How debuggers generally work and how to debug code.

Could these things be taught equally well or better in an undergraduate seeing
using rust? Honestly I don't know; I know very little about Rust. I can say
that I think C++ is a worse language for this purpose because of the
language's complexity and because of features that aren't well suited for the
above purposes.

I have heard, for instance, that's it's actually very difficult in rust to
write a linked list without dropping to unsafe code. I would consider this a
bad thing for the above purposes.

~~~
kqr
> * How the code is executed on modern hardware and operating systems.

Does _anyone_ know this at this point? With pipelining, out of order
execution, vectorisation, register renaming, speculative execution, buffered
micro-op fusing and what have you, it's very hard to say general things about
how the code executes on the actual hardware.

~~~
yjftsjthsd-h
Perhaps, "Understand the model of how code pretends to be executed"?
Pipelining, etc. are meant to produce the same results as the older/simpler
systems. You need to understand that that's not quite reality anymore, but as
a basic model it's fine.

~~~
kqr
Sure, but at that point you are content with learning "the x86 virtual
machine" \-- and is that fundamentally different from being content with
learning "the Java virtual machine"?

I'm arguing that it's a matter of degree, not of kind. People make it seem
like it's the latter.

~~~
barrkel
It's different in kind. The JVM completely abstracts away things like class
loading from the perspective of bytecode - that stuff seems to happen like
magic. Ditto exception handling, stack frame linkage, memory allocation, etc.

Viewing all of code and data living together in a big array is important, I
think. You don't understand e.g. dynamically generated thunks and shims
without seeing the duality of code and data at the execution level.

------
ChrisSD
If you want to "think like a computer" then learn assembly, not C. I'm not
joking.

In my experience young devs using C get very confused about wtf pointers are
really about and what's the deal with the heap, stack, etc. Whereas they
understand the concepts better in assembly despite the verbosity.

I'm not arguing for a deep understanding of assembly but if the goal is to
"think like a computer" than at least a basic understanding is incredibly
helpful. Or at least less confusing than C.

~~~
kahlonel
I partly agree with you. But its a fact that you can't just start learning
assembly if you have never learned C in the first place. So, young devs,
please start learning C first.

~~~
mettamage
This is false. I _have_ learned the basics of assembly without knowing C
first. My experience before learning assembly was: Java, Python and some
Objective-C (without knowing pointers). So if your point is that you need to
learn programming first, then maybe that is true but I highly doubt it. But I
can't refute that with my own experience.

Here wa my roadmap:

(1) I first learned assembly by learning computer architecture from
Tanenbaum's book -- Structured Computer Organization -- and related course at
the Vrije Universiteit Amsterdam. This taught me a toy architecture (Mic1) but
it give me a rough idea of how assembly worked.

(2) Then, later I took a course in binary and malware analysis and all that we
were required to do was to read x86 assembly in IDA and interact with it via
GDB -- and using the command: layout asm, which gives a layout for all the
register values and upcoming instructions.

And once I have a debugger available and understand it well enough, I can
learn quite well since I can make little predictions and check if they are
right or wrong, and so on.

~~~
Santosh83
I learned assembly as my first ever programming language and it was just fine.
Assembly tends to be simple and can get you coding quickly and understanding
the machine as well. It's of course an awfully inefficient way to code in
general and that's why we have HLLs but its not true that you need to learn at
least one HLL before learning assembler.

------
hoosieree
C is tightly coupled and co-evolved with the Von Neumann architecture. If you
understand C you can better understand _that_ architecture, but it's far from
the only one. Beyond the world of single core CPUs, systems rarely hyper-
specialize to the point that the C/Von Neumann system has (focusing all
energies on ALU throughput). And the larger (and more distributed) systems we
build, the less they resemble Von Neumann machines.

So while it's realistic to embrace C for many tasks, it's wrong to convince
yourself that "the rest follows" from C.

~~~
dsjoerg
Can you recommend some non-Von Neumann architectures worth learning about?
Maybe you agree with these suggestions I found by Googling, or maybe you have
other ideas: [https://stackoverflow.com/questions/1806490/what-are-some-
ex...](https://stackoverflow.com/questions/1806490/what-are-some-examples-of-
non-von-neumann-architectures)

~~~
mettamage
I second this, I want to know some recommendations too. Are there university
courses out there that teach non-Von Neumann architectures? And what are the
application areas? I could Google myself but my experience with HN is that if
someone knows a good course, then it is a good course. While with Google, not
so much.

~~~
carapace
The Mill architecture:

> the mill uses a novel temporal register addressing scheme, the belt, which
> has been proposed by Ivan Godard to greatly reduce the complexity of
> processor hardware, specifically the number of internal registers. It aids
> understanding to view the belt as a moving conveyor belt where the oldest
> values drop off the belt and vanish.

[https://en.wikipedia.org/wiki/Mill_CPU_Architecture](https://en.wikipedia.org/wiki/Mill_CPU_Architecture)

------
krinchan
I still can point to the exact point in my college career that took me to a
whole new level of understanding how to program in Java or Python to
understanding how things like Garbage Collection, Threads, and other
abstractions actually worked. It was an elective I took on Graphics
Programming and it was all in C and OpenGL.

Being without GC, I learned the trade offs. Obviously, being able to
explicitly allocate and free memory was a big deal. But at the same time, I
learned to appreciate the complexity and pitfalls of GC.

Threads are great in Java (as are their parallels in other languages): this is
the work to do, put the results here, and everything is cleaned up. Meanwhile,
just trying to get the results back from a forked process was CRAZY.
Implementing and managing my own shared memory to pass messages back and
forth...wtfbbq.

"Think like a computer," not really. More like, "understand what all goes into
a thread, an async call, or a garbage collector. Gain more understanding into
the corner cases and exactly how much this thing is doing for you. So maybe
setting something to null or pre-allocating objects to reduce heap work isn't
that big a deal."

C taught me to be patient with higher level languages, to better understand
what they were doing for me, be able to reason about how they may be doing
these things wrong, and to think critically about how to coax these features
into behaving the way I want them to.

Really any lower level language can teach these things. The point here is that
C is a nearly universal language that can teach you to reason about these
things.

------
rossdavidh
I think learning C is a fine thing to do, when the alternative is to learn
nothing at all, as knowing C is a quite useful skill. However, a more
substantive question should be, "should you learn C next, or R?" or "should
you learn C next, or neural networks"? or "should you learn C next, or
Bayesian statistics"? It may be that C is more urgent and important to learn
than any of those, but if you find that people are not, it is not necessarily
the case that they don't see the usefulness of it. They may just have a finite
amount of time, and learning Mandarin Chinese ranks higher for them, not least
so they can better understand how natural language processing would work if
you're involved with non-European languages.

------
loeg
By all means teach and use C (I do!), but please teach students to refer to
C11 or C99, not C89.

~~~
waynecochran
Yes. At least C99.

Also, the blog throws in "and C++" in parentheses. C++ is another beast
altogether -- it diverged from C a long time ago -- read Scott Meyer's
"Effective Modern C++" if you think C and C++ bear any resemblance.

------
kqr
I feel like this article makes two strong arguments in favour of C:

1\. You need to know C because C is popular, and

2\. You need to know C because C is a lowish-level language.

I can't very well argue with the first point -- indeed, nearly everything
fundamental is made in C or the C-like subset of C++ still -- but I oppose
myself to the second.

I do think you should learn a lowish-level language, but there are good
reasons to make that language something like Ada instead; something high-level
enough to have concurrency primitives yet low-level enough to force you to
consider the expected ranges of your integers and whether or not you want
logical conjuctions to be short-circuiting. Something high-level enough to
have RAII managed generic types, yet low-level enough to let you manipulate
the bit layout of your records. High-level enough to have exceptions and a
good module system for programming in the large yet low level enough to have a
built in fixpoint type and access to machine code operations.

Unless you target C specifically for its popularity, there are other options
out there, filling the same gap.

~~~
Avshalom
>>Ada instead; something high-level enough to have concurrency primitives yet
low-level enough to force you to consider the expected ranges of your integers

In practice Ada programmers, because they actually have a proper method of
expressing integer ranges, are going to be much more considerate of such
things.

------
RcouF1uZ4gsC
C++ and Rust address most of the issues presented in the article (with the
exception of being able to read the source code of existing software).

My very controversial opinion is that C is obsolete for new programming
projects. For example, everything that C can do, C++ can do and
better/safer/faster. Rust is also getting there (if not there already). C is
not Pareto optimal anymore.

~~~
ryanianian
Maybe depends on the project. Writing a web API in C almost certainly isn't
pareto-optimal. A linux/raspberry-pi driver for your hobby-project that needs
to interact with other low-level linux-based software however, C is probably
the most efficient fit.

Rust (and maybe Go) do seem like very good long-term replacements for C, but
imho it's too early to say that. Until there's a "full stack" of software (OS
to user-space/desktop), you still kinda need to know C if you want to be able
to understand how your whole computer works.

~~~
Inityx
I don't see Go as any sort of replacement for C. The fact that it's garbage-
collected means that it's really not suitable for use in embedded or kernel
programming.

AFAICT, Rust was created to be a safer C, and Go was created to be a faster
Python; completely separate domains.

~~~
ryanianian
You’re quite right.

------
brudgers
_C is so unfashionable that the authors have neglected to update it in light
of 30 years of progress in software engineering._

Words escape me.

~~~
tomsmeding
Out-of-context quote. (Even if the original is slightly strangely written.)
The "update it" refers to the _book_ The C Programming Language, not to the C
language itself; C itself has seen an update as recently as 2011.

~~~
Avshalom
It's not out of context at all. It's bizarre to assume that every book ever
written about a subject will be updated constantly by it's (currently
septagenarian) authors in perpetuity and/or that a failure to update it is an
indication of the culture in general and not the authors having literally
anything else to do.

It's not like books on C stopped being written by 1990.

~~~
saagarjha
Yes, but _The C Programming Language_ is almost always recommended as _the_
book to read.

------
SAI_Peregrinus
> Forsaking C means forsaking anything below the level of abstraction at which
> one happens to currently work.

That's trivially true. Pick anything as your bottom abstraction layer, you can
almost certainly find something below. Unless you're working on the
foundations of mathematics or trying to come up with theories of quantum
gravity you haven't hit the bottom of the abstractions.

It's also not as though C is the bottom layer even for programming. There's
assembly. Then HDLs like Verilog or VHDL. Then electrical engineering... You
have to stop somewhere. My knowledge spans from some electrical engineering
through C up to Python/Java/Lisp levels, but I don't (currently) know much of
anything about Javascript or actual semiconductor engineering or more than
basic physics...

C is pretty good as a foundation for programmers. It's terrible as a
foundation for computer engineers, and it's pretty much at or above the
ceiling for what's expected of electrical engineers. It's not guaranteed to
remain a good foundation for programmers. Massively parallel architectures
like GPUs don't tend to fit well into C's abstract machine model.

------
elihu
> Forsaking C means forsaking anything below the level of abstraction at which
> one happens to currently work.

This is mostly true today, but I hope that over time we'll see more languages
fill the gap between hardware and high-level languages. There's no fundamental
reason why that middle layer has to be in C, we just have had a shortage of
viable alternatives.

~~~
pcwalton
There's no shortage of viable alternatives. C++ is significantly more popular
than C these days, and the gap widens every year.

~~~
AlexandrB
The problem is you can't learn all of C++. I've been coding in it for the
better part of a decade and I still run into weird corners that don't make
sense regularly.

C is much more compact.

~~~
waynecochran
Amen. Every time I think I have my head wrapped around C++ a new version comes
out or Scott Meyers writes a book and I realize how ignorant I am about C++.
No one really know all of C++.

I bet Stroustrap occasionally sees some C++ code and says "huh ... I didn't
know you could do that."

~~~
kqr
> "huh ... I didn't know you could do that."

To be fair, that is not an entirely uncommon thing to say when watching a user
work with something you made.

------
x0re4x
I've heard C language was designed with the idea that the programmer knows
what he is doing and the programming language shall not be standing in his
way.

For me the cost of forsaking C would be not to experience 100% programming
freedom/power (which comes with 100% responsibility). And yes, C also gives
you the freedom to do any nonsense :)

I was always fascinated how little resources are needed to run C programs,
here an example (not by me): [https://github.com/barteksalsa/avr-
tiny12-disco/blob/master/...](https://github.com/barteksalsa/avr-
tiny12-disco/blob/master/leds.c) ATTiny12 mikrocontroller with: 1 KiB program
flash rom, 32 bytes of "ram", 3 level hardware stack

~~~
joezydeco
The infamous quote goes

 _" The C language combines all the power of assembly language with all the
ease-of-use of assembly language."_

~~~
x0re4x
Do you have a specific example? I wrote programs in Z80, AVR, x86/amd64 and
MIPS assembly. In my experience writing C is MUCH easier.

~~~
joezydeco
But C allows for just as much foot-shooting, thus the joke. (The quote is
meant to be humorous)

------
Avshalom
C does not help you think like a computer. It has no language level support
for memory hierarchies or parallelism. It doesn't about know about integer
overflow.

~~~
BeeOnRope
While I disagree with your other claims, I'm especially curious about this
one:

> no language level support for memory hierarchies

By this, I assume you mean cache hierarchies (for example). What languages do?

~~~
Avshalom
None other than various assemblies thanks to the "influence of C" convincing
people that a flat (essentially contiguous) endless memory space was "how a
computer works"

~~~
Rusky
Typical assembly languages hardly do anything more with cache hierarchies than
C does.

------
fractallyte
No mention of Forth? Small, close to the metal, easier than C, and just as
capable. But it's from that alternative universe of computing (also inhabited
by Lisp and Smalltalk).

A couple of well-known articles/discussions about that universe:

A Forth Story:
[https://news.ycombinator.com/item?id=3813966](https://news.ycombinator.com/item?id=3813966)

Lisping at JPL:
[https://news.ycombinator.com/item?id=7989328](https://news.ycombinator.com/item?id=7989328)

------
asimpletune
I know these guys and they provide legit college-level CS education. If any of
you live in the bay and have an education stipend at work, or just want to
level up, then I highly recommend.

------
fellellor
Most of the C language texts that I have come across just seem to teach how to
use the language, say pointers etc. Maybe there is something about how to use
make.

I've found it hard to go from there to link up with the more abstract stuff.
Not so with python, because the mental energy I spend reading python code is
very little, which enables me to move very fast.

Reading sklearn source has been a revelation to me. I can't imagine having to
read a similar high level equivalent in C.

------
karmakaze
TL;DR

    
    
      We give students four reasons for learning C:
    
      1. It is still one of the most commonly used languages outside of the Bay Area web/mobile startup echo chamber;
      2. C’s influence can be seen in many modern languages;
      3. C helps you think like a computer; and,
      4. Most tools for writing software are written in C (or C++)
    

[Not really TL, but good context for reading comments referencing the numbers]

------
tempodox
> There isn’t even a cute C animal in C’s non-logo on a C decal not stuck to
> your laptop.

At least there is a cute image presenting “The C Programming Language” in the
context of Plan 9:
[http://9front.org/img/000000wq9nh.png](http://9front.org/img/000000wq9nh.png)

~~~
sotojuan
I guess Cirno counts, her name starts with C!

------
auvrw
for rubyists and pythonistas interested in writing more C while not losing the
convenience of scripting, lua is probably worth picking up along the way. the
following is the C-interop samples from Programming in Lua

[https://github.com/ransomw/exercises/tree/master/lleaves/plu...](https://github.com/ransomw/exercises/tree/master/lleaves/plusc)

... only gripe with this article is the couple of "... and/or C++" clauses: i
personally hope to be forgiven for forsaking C++ for new projects, because it
is not the 1970's anymore, and i suppose there are alternatives for almost
every use case as well as externs for plain-C interop with existing C++ libs.

it's more like C+{100} so many are the additional feature-ughs.

------
seaurchin
This is a really fun (and relatively short) c programming book:
[https://www.amazon.com/Expert-C-Programming-Deep-Secrets-
ebo...](https://www.amazon.com/Expert-C-Programming-Deep-Secrets-
ebook/dp/B00E0LASCU/)

~~~
nallerooth
This book is really good, and I'd say that a couple of weeks after reading K&R
- you should read this one (given that you fiddle with C during those weeks).

------
GoToRO
About not being updated: there are linters, and if you impose a rule that you
can only check in code that passed the linter, then essentially you are
writing a newer, better version of C.

------
purplezooey
C is like English. You know it without having to grab a book. It just flows
out of you naturally.

~~~
flavio81
how can one of the languages with the most tricky syntax to parse "flow
naturally"?

and I say this as somebody proficient in C.

------
smadge
Learn basic digital circuits. Learn an assembly language. Learn C. Implement a
simple interpreted language.

You don't have to reinvent every level of the stack and connect it all
together(your imagination can fill in the gaps), but this removes the mystery
of computing.

------
inetknght
> _The most recent edition of the canonical C text (the excitingly named The C
> Programming Language) was published in 1988_

So... C99 and C11 aren't things?

~~~
kazinator
C99 and C11 are things; just not the kinds of things for which you update a
classic book that describes a reasonably nice language that some of us still
prefer to work with (over those things).

From the K&R2's [1988] Preface:

 _" We have tried to retain the brevity of the first edition. C is not a big
language, and it is not well served by a big book"_.

Well, that line would go out window with a C11 update. Along with, from the
introductory chapter:

 _C is not a "very high level" language, nor a "big" one, and is not
specialized to any particular area of application._

Oops; the page count in ISO C more than doubled.

 _But its absence of restrictions and its generality make it more convenient
and effective for many tasks than supposedly more powerful languages._

The absence of restrictions, whereby C programmers were wrestling particular
behaviors out of their code with the cooperation from a particular set of
compilers, has lately been turned into a license to wreck non-portable code
that used to work for decades.

Who wants to update a classic book in the environment in which you have to
warn the reader of undefined behavior at every turn.

~~~
lalaland1125
How do you deal with multi-threading in C89? If you rely on POSIX for your
threading support, couldn't you argue that you are now dealing with something
just as complicated, if not more complicated than C11?

Sometimes there is just unavoidable complexity for extremely useful features
like thread support. Keeping stuff like that out of the standard doesn't
necessary make the language simpler if you are forced to rely on other
standards anyways ...

~~~
kazinator
> _How do you deal with multi-threading in C89?_

Certainly not by means of the abhorrent garbage that has been added to C for
threading.

POSIX is a standard. POSIX started as a branch of the Unix C library that
didn't belong in the language. So for instance that's where "open" and "ioctl"
went, while "printf" and "malloc" went to C.

There is no need for C to start adding its own versions of POSIX requirements
(let alone toy versions); it just adds complexity.

Now what it means is that we can end up with some mongrel project where we
have POSIX threads being spawned in one module, ISO C threads in another and
so on.

------
eptcyka
I fail to see how an understanding of C would make one better at understanding
userspace process scheduling or text editors.

~~~
vvanders
May I kindly lay out VSCode and Atom as a counter to your second example?

Knowing your allocations and performance at a low level can influence usage of
a high level language and have a huge impact.

