[Note: This is written with Ruby programmers in mind, but it applies to anyone using similar high-level languages]
Most programming languages today shroud the machine executing their programs in several layers of abstraction. Programmers don’t care much about it, having been taught to leave all the messy details to the interpreters, compilers and virtual machines.
So, C. It’s a rather old language and it doesn’t offer very much in the way of features. In fact, compared to Ruby, it’s downright bare. It clearly falls in the realm of system programmers and hardware wizards, both places where a Ruby programmer isn’t exactly a common sight. Why do you, a Ruby programmer, need to learn C?
Programming in C for the first time seems to be a chore. There are many details about your Code you need to keep track of. And C doesn’t even lend you much of a hand when programming. There are no iterators, memory management is done manually, and handling strings correctly is akin to walking through a minefield with a hood over your head. While on fire. And being chased by a pack of wild dogs.
It is easy to see why people soon went on to create languages that were much nicer to program in. And it is hard to see why you would want to write code in it.
Well, for one, C hands you the key to a wealth of libraries that are all accessible from C, even if they aren’t written in it. C has sort of established itself as the lingua franca between languages. When you call OCaml from Ruby (or vice versa), the bridge is built in C. Even Java and .NET offer a C interface, so you can communicate with all those other languages and libraries. And yes, the ‘dl’ library allows you to call C from Ruby, but what if you need to provide a callback function? Then you’re stuck, unless you know C (or you know someone who knows C).
But there is a second, more important, reason why you want to learn C.
When it comes down to their basic architecture, pretty much every computer sold today is based on the Von Neumann architecture. It has been improved and modified since its invention in the 50s, but the core attributes are still present. And every assembler language used to control those computers is highly adapted to it. Therefore, if you learn and program in an assembler language, you’re very much aware of how the hardware underneath it operates. You’re aware of every nuance and peculiarity it exhibits, you know what is going on underneath. This enables you to write highly efficient implementations for that computer.
The thing is though, computer architectures come and go, and with them, their assembler languages go out of fashion, and new ones are introduced (like the recent switch from PowerPC to the x86 architecture by Apple). To avoid having to port code and programs from one assembler to another, Dennis Ritchie invented what would later be known C. It is in its very essence just a thin layer over assembler language - thick enough that you can port code written in C to another computer without much fuss, but still thin enough that the hardware is at your very fingertips.
And this is what makes C worth knowing. It represents the very Von Neumann architecture your computer runs on. Understanding C means understanding your machine. It means you can now rewrite that performance bottleneck in your Code that you simply can’t get any faster in pure Ruby. You can now dive into the guts of MRI and at least have a fighting chance to understand what’s going on.
You’ll also know what it means to program with hardly any safety nets. No garbage collector to clean up any stray blocks of memory that you forgot to free, no virtual machine that checks your every step and makes sure you don’t fall of a cliff.
All in all, it is a very raw, almost visceral experience. But, to paraphrase Eric S. Raymond, C is worth learning for the profound enlightenment experience you will have when you finally get it; that experience will make you a better programmer for the rest of your days, even if you never actually use C itself a lot.