Learning C, reducing fear.

I have a confession to make. At one point in my career, I was a mediocre programmer. I might say that I still am, only in the context of being a harsh grader. I developed a scale for software engineering for which I can only, in intellectual honesty, assign myself 1.8 points out of a possible 3.0. One of the signs of my mediocrity is that I haven’t a clue about many low-level programming details that, thirty years ago, people dealt with on a regular basis. I know what L1 and L2 cache are, but I haven’t built the skill set yet to make use of this knowledge.

I love high-level languages like Scala, Clojure, and Haskell. The abstractions they provide make programming more productive and fun than it is in a language like Java and C++, and the languages have a beauty that I appreciate as a designer and mathematician. Yet, there is still quite a place for C in this world. Last July, I wrote an essay, “Six Languages to Master“, in which I advised young programmers to learn the following languages:

  • Python, because one can get started quickly and Python is a good all-purpose language.
  • C, because there are large sections of computer science that are inaccessible if you don’t understand low-level details like memory management.
  • ML, to learn taste in a simple language often described as a “functional C” that also teaches how to use type systems to make powerful guarantees about programs.
  • Clojure, because learning about language (which is important if one wants to design good interfaces) is best done with a Lisp and because, for better for worse, the Java libraries are a part of our world.
  • Scala, because it’s badass if used by people with a deep understanding of type systems, functional programming, and the few (very rare) occasions where object-oriented programming is appropriate. (It can be, however, horrid if wielded by “Java-in-Scala” programmers.)
  • English (or the natural language of one’s environment) because if you can’t teach other people how to use the assets you create, you’re not doing a very good job.

Of these, C was my weakest at the time. It still is. Now, I’m taking some time to learn it. Why? There are two reasons for this.

  • Transferability. Scala’s great, but I have no idea if it will be around in 10 years. If the Java-in-Scala crowd adopts the language without upgrading its skills and the language becomes associated with Maven, XMHell, IDE culture, and commodity programmers, in the way that Java has, the result will be piles of terrible Scala code that will brand the language as “write-only” and damage its reputation for reasons that are not Scala’s fault. These sociological variables I cannot predict. I do, however, know that C will be in use in 10 years. I don’t mind learning new languages– it’s fun and I can do it quickly– but the upshot of C is that, if I know it, I will be able to make immediate technical contributions in almost any programming environment. I’m already fluent in about ten languages; might as well add C. 
  • Confidence. High-level languages are great, but if you develop the attitude that low-level languages are “unsafe”, ugly, and generally terrifying, then you’re hobbling yourself for no reason. C has its warts, and there are many applications where it’s not appropriate. It requires attention to details (array bounds, memory management) that high-level languages handle automatically. The issue is that, in engineering, anything can break down, and you may be required to solve problems in the depths of detail. Your beautiful Clojure program might have a performance problem in production because of an issue with the JVM. You might need to dig deep and figure it out. That doesn’t mean you shouldn’t use Clojure. However, if you’re scared of C, you can’t study the JVM internals or performance considerations, because a lot of the core concepts (e.g. memory allocation) become a “black box”. Nor will you be able to understand your operating system.

For me, personally, the confidence issue is the important one. In the functional programming community, we often develop an attitude that the imperative way of doing things is ugly, unsafe, wrong, and best left to “experts only” (which is ironic, because most of us are well into the top 5% of programmers, and more equipped to handle complexity than most; it’s this adeptness that makes us aware of our own limitations and prefer functional safeguards when possible). Or, I should not say that this is a prevailing attitude, so much as an artifact of communication. Fifty-year-old, brilliant functional programmers talk about how great it is to be liberated from evils like malloc and free. They’re right, for applications where high-level programming is appropriate. The context being missed is that they have already learned about memory management quite thoroughly, and now it’s an annoyance to them to keep having to do it. That’s why they love languages like Ocaml and Python. It’s not that low-level languages are dirty or unsafe or even “un-fun”, but that high-level languages are just much better suited to certain classes of problems.

Becoming the mentor

I’m going to make an aside that has nothing to do with C. What is the best predictor of whether someone will remain at a company for more than 3 years? Mentorship. Everyone wants “a Mentor” who will take care of his career by providing interesting work, freedom from politics, necessary introductions, and well-designed learning exercises instead of just-get-it-done grunt work. That’s what we see in the movies: the plucky 25-year-old is picked up by the “star” trader, journalist, or executive and, over 97 long minutes, his or her career is made. Often this relationship goes horribly wrong in film, as in Wall Street, wherein the mentor and protege end up in a nasty conflict. I won’t go so far as to call this entirely fictional, but it’s very rare. You can find mentors (plural) who will help you along as much as they can, and should always be looking for people interested in sharing knowledge and help, but you shouldn’t look for “The Mentor”. He doesn’t exist. People want to help those who are already self-mentoring. This is even more true in a world where few people stay at a job for more than 4 years.

I’ll turn 30 this year, and in Silicon Valley that would entitle me to a lawn and the right to tell people to get off of it, but I live in Manhattan so I’ll have to keep using the Internet as my virtual lawn. (Well, people just keep fucking being wrong. There are too many for one man to handle!) One of the most important lessons to learn is the importance of self-mentoring. Once you get out of school where people are paid to teach you stuff, people won’t help people who aren’t helping themselves. To a large degree, this means becoming the “Mentor” figure that one seeks. I think that’s what adulthood is. It’s when you realize that the age in which there were superior people at your beck and call to sort out your messes and tell you what to do is over. Children can be nasty to each other but there are always adults to make things right– to discipline those who break others’ toys, and replace what is broken. The terrifying thing about adulthood is the realization that there are no adults. This is a deep-seated need that the physical world won’t fill. There’s at least 10,000 recorded years of history that shows people gaining immense power by making “adults-over-adults” up, and using the purported existence of such creatures to arrogate political power, because most people are frankly terrified of the fact that, at least in the observable physical world and in this life, there is no such creature.

What could this have to do with C? Well, now I dive back into confessional mode. My longest job tenure (30 months!) was at a startup that seems to have disappeared after I left. I was working in Clojure, doing some beautiful technical work. This was in Clojure’s infancy, but the great thing about Lisps is that it’s easy to adapt the language to your needs. I wrote a multi-threaded debugger using dynamic binding (dangerous in production, but fine for debugging) that involved getting into the guts of Clojure, a test harness, an RPC client-server infrastructure, and a custom NoSQL graph-based database. The startup itself wasn’t well-managed, but the technical work itself was a lot of fun. Still, I remember a lot of conversations to the effect of, “When we get a real <X>”, where X might be “database guy” or “security expert” or “support team”. The attitude I allowed myself to fall into, when we were four people strong, was that a lot of the hard work would have to be done by someone more senior, someone better. We inaccurately believed that the scaling challenges would mandate this, when in fact, we didn’t scale at all because the startup didn’t launch.

Business idiots love real X’s. This is why startups frequently develop the social-climbing mentality (in the name of “scaling”) that makes internal promotion rare. The problem is that this “realness” is total fiction. People don’t graduate from Expert School and become experts. They build a knowledge base over time, often by going far outside of their comfort zones and trying things at which they might fail, and the only things that change are that the challenges get harder, or the failure rate goes down. As with the Mentor that many people wait for in vain, one doesn’t wait to “find a Real X” but becomes one. That’s the difference between a corporate developer and a real hacker. The former plays Minesweeper (or whatever Windows users do these days) and waits for an Expert to come from on high to fix his IDE when it breaks. The latter shows an actual interest in how computers really work, which requires diving into the netherworld of the command line interface.

That’s why I’m learning C. I’d prefer to spend much of my programming existence in high-level languages and not micromanaging details– although, this far, C has proven surprisingly fun– but I realize that these low-level concerns are extremely important and that if I want to understand things truly, I need a basic fluency in them. If you fear details, you don’t understand “the big picture”. The big picture is made up of details, after all. This is a way to keep the senescence of business FUD at bay– to not become That Executive who mandates hideous “best practices” Java, because Python and Scala are “too risky”.

Fear of databases? Of operating systems? Of “weird” languages like C and Assembly? Y’all fears get Zero Fucks from me.

About these ads

7 thoughts on “Learning C, reducing fear.

  1. Do use an ML with good documentation and community. When I was learning SML in class it didn’t have much of either and it was very painful.

  2. I find your blog extremely interesting , informative and more importantly very true (according to my perception). I keep on sharing them with some like minded people, but there is one request. Each of your post is too lengthy, especially when one is reading, it appears like you are discussing something with somebody who is not giving you a chance to speak. If you can break up slightly orthogonal topics into separate posts, it would be even more interesting.

    The length feedback apart, if you are ~30 yrs, your thinking appears like somebody with 30 yrs of experience! great writing.

  3. I will add to the comment above, I enjoy reading your posts. But I have been following you for a while now, and besides the post about snakes and creationism, it sounds like you are always angry and its exhaustive. I agree on most of your points but once in a while a light post will make your reading fantastic.

  4. I agree. I recently started doing a bit more learning hacking in Python and have been drawn back to C again. It’s been well over a decade since I wrote anything more than a simple C program, but IMO, _all_ serious programmers should at least learn enough C to be able to read it and understand it at least at a very basic level.

    You’re right, C isn’t going away in 10 years or 50 years, most likely. It is the bedrock of UNIX type systems of all flavors (including OS X / iOS) and is here to stay. Understanding how the machine functions as close to the bare metal as possible is crucial to understanding why and how higher languages developed and exist. One does not have to be an expert, although there is plenty of work to be done there. I can almost guarantee, you will get at least a .1 – .2 boost using your scale if you really dive into C.

    It’s the reason I have been focusing a bit more on relearning it myself. Also, I’d like to add, that you can build very complex, clean applications in C, despite all the low level details like malloc etc. C provides excellent abstractions for a low-level language such as structs and a very simple way of building applications modularly through its macro and header file system.

    Also, you can drop down into assembly for a line or two for optimization. Which can be a great stepping stone to getting even closer to the metal with assembly (I don’t think anyone does straight machine language anymore, but I could be wrong).

  5. What is your preferred way of learning new languages? And specifically for C, what approach and “path” are you taking to learning it?

    • So, based on the info from your previous post, you’re using Zed Shaw’s Learn C the Hard Way. Anything to add, in the sense of learning method or other resources?

      I learned the elementary constructs of (imperative) programming in college by using C, but would like to expand the knowledge and see some more advanced and real-life uses. Also, it’s always interesting to glimpse other programmers’ language absorption methods…

  6. I was a C programmer about 10 years ago. I was a bad C programmer: I left file handles open and my code leaked memory like a sieve. As much as I tried to make my code readable, it turned out to be write-only. The few bits of code that I’ve gone back and looked at again make me embarrassed, and the stress of trying to debug C code in emergency situations still haunts me to this day.

    I’m a far better programmer now, simply by virtue of having ten more years of experience. Every once in a while, I go back and crack K&R, simply because I would like to prove to myself how far I’ve come, but every time I do, I realize that the time that I would have to spend to really do the job right is just too great. I don’t *want* to be a C programmer again; the only places where C code is the right answer are not areas of programming that ever interested me… it may be true that there are “large sections of computer science that are inaccessible if you don’t understand low-level details like memory management.”, but learning C is necessary but not sufficient to understand those. There are also *vast* areas of computer science that *don’t* require a knowledge of memory management.

    I’m very leery of the intellectual machismo that I’ve seen among a number of C programmers. Yes, there are benefits to understanding what the machine is doing down to the bare metal, and yes the language can produce blazingly fast machine code, but it’s also *far* too easy to lose the forest for the trees and write code in C that would be orders of magnitude more supportable in a higher level language.

    Computers are four orders of magnitude faster than they were when K & R wrote it, and some of the trade-offs that they made between performance and code safety simply don’t hold any more.

    There is no doubt that C is a beautiful language, in some respects. It’s spare and stark and sharp, but a certain amount of its beauty also lies in comparison to the languages that were around it when it was written. It is also very avowedly a language that gives you “rope enough to hang yourself with”, and having been hanged from the neck until dead on enough occasions, I view it with a very leery eye.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s