— Wilson Page (@wilsonpage) March 7, 2016
Since I like to add interesting information to conversations, I looked at the answers first, to make sure no one had mentioned the answer I had in mind. And surprisingly enough, no one had indeed mentioned my suggestion: C!
Wilson also asked for the reasons why I would suggest C as a useful language. I tweeted some:
@wilsonpage you get to understand the base of all the systems we deal with, and its deficiencies! And why JS is so cool too 😉
— ⎛⚆_⚆⎠ (@supersole) March 7, 2016
@wilsonpage if you want to write low level / efficient code, learning C is a good idea. Also for WebGL shaders, asm.js, arduino, …
— ⎛⚆_⚆⎠ (@supersole) March 7, 2016
but Twitter’s interface is horrible, and I feel they deserve a whole entire post, sooooo…
This is why C is a useful language
All the operating systems we interact with on a daily basis are built with C at some point. If not directly built with C, they are built using C inspired/derived languages, such as C++ or Objective C.
There are newer languages such as Java, C#, Rust or Swift that try to build on the experience of C programming, and try to solve the most common errors–often memory allocation and string handling. If you understand how C works, you understand the motivation for these new languages. You also understand better security issues–when someone talks about buffer overflows and about dumps, it doesn’t just sound like obscure jargon to you. Things make sense.
As web developers we are usually happy in our top level abstraction layer: the browser or node.js, or maybe even Electron. But if you try to dig a little bit deeper you’ll soon stumble upon binary stuff. Which is more often than not C (in node.js’s case) or, again, a C-derived language. Understanding how to interface with these parts is great! And often, modules that bind a library or API to JS are not entirely documented. Being able to look at code and understanding it is a great advantage. Not only does it empower you as a user, it could even help you modify the bindings and make them do whatever you need, by using your knowledge of the two worlds: JS and binary. This is the same case with Ruby, Python, … you name it.
You can do really powerful and superoptimised things in C; a frequent example is processing lots of data with little overhead. Normally, in our abstracted world we delegate tasks such as dealing with the stack or allocating and deallocating memory to the script interpreter of choice. In C you have to be aware of this, which can be a huge hassle, but if you understand those aspects you can manipulate them to your advantage. Allocate the right amounts of stack memory and inline a bunch of calls and you can churn away lots of data without having to incurring on that overhead I mentioned above.
Another example of why knowing C will open doors for you is WebGL shaders. They are not written in C, but their syntax and semantics are very similar. They are relatively small programs that are designed to be run in parallel in many GPU cores at the same time. They are also uncannily similar to data crunching algorithms as in being essentially a lot of arithmetic operations. But you need to understand the limitations: using the proper data and operator types, no dependencies with the results from other calculations, no loops, costs of accessing memory for texture reads/writes, etc. You have to be quite close to the ‘metal’, but in exchange you get incredible performance.
Likewise, if you want to get into hardware programming, you’ll probably go through an Arduino first, but once you outgrow their IDE you might want to remove that layer and go to the next one: it will be written in C, and you might be able to save on a few Kbs of memory by removing abstractions here and there. Software for embedded systems is often written in C or C-derivatives which gets then compiled into some kind of binary or “transpiled” and written to programmable hardware.
And if you remove C you find Assembler. C is the closest to Assembler code without being Assembler. As I said, it exposes much of the metal, so much that you can often find bits of Assembler embedded inside C code. You would think that this is for when you get really specialised, but not really. The Linux kernel has many parts written in C + assembler. Many written in assembler only, as e.g. the boot sequence. There are even operating systems entirely written in Assembler, such as MenuetOS.
Learning Assembler might probably be totally useless on a day to day practical basis, but it will enlighten your understanding of general computing, and concepts such as registers, RAM, instruction sets, CPU cores and memory speed will not sound alien to you anymore, and again, you understand what limitations exist. When you stop thinking of a computer as a “black box that does things” and understand all the different subsystems and how they relate to each other, you start thinking about programming in a completely different, more nuanced way.
And at some point you will reach the epiphany moment, and realise that it is actually a miracle that anything works at all, with so many layers and moving parts written by so many different people. And understand why the Web is such a great space to be in, and why abstractions are good because otherwise we would all be trying to debug why our mallocs are failing and not getting anything done!
Happy programming in whatever language you like! \o/