Structure and Interpretation of Computer Programs, aka SICP, aka “The Wizard Book.” What a legendary piece of work! So today, after years going without any mentioning of this book, those initials came back in a casual chat I had with a colleague of mine. Nostalgia time… so, so many memories came back to me!
More so when I decided to have a quick watch to the recordings of the ‘85 SICP lectures at MIT, freely available on YouTube. The book itself is also freely available from a webpage that has stayed untouched since 1999 and almost looks like a relic from a distant era… a bygone era in which the goals and ethos of the WWW were still alive.
Web 1.0 and 1980s nostalgia aside, I wanted to talk to you guys about my story with SICP. That book shaped my way of thinking way beyond computer science… It’s got very nice intuitions around semiotics which I’ve always found very interesting to apply to natural languages. In any case, I hope that telling you my story might spark your interest in reading it and maybe even watch the lectures… In my very, very personal opinion, SICP is a must if you’re interested in programming, even if you’re more into a more hands-on approach rather than a theory-driven coder.
OK, where do I start?? My goodness, I never felt so unsure about how to deal with a blog post before… This is very emotional for me, believe me.
It is emotional because I still remember who pointed me to that book. I was a part of certain programming subforum and IRC chat room back in 2007-ish. I was becoming a full-time Linux user and, after a hiatus of several years not coding a single line, well… Linux reindled my interest. I was learning C back then while coding simple stuff in Python and Perl, mostly. My background was BASIC and pre-.NET Visual Basic… I remember struggling a lot in how to organize my code around procedures and data structures in C…
“You’re a Linguistics undergrad, right?” My guide asked me one day on IRC.
“Yes, I am, why?”
“Take a look at Scheme and SICP… I think you’ll like it a lot.”
Of course that’s a redramatization; I don’t remember the exact conversation… I do remember that this person told me that the abstactions-oriented approach of SICP and the bare syntax of Lisp would blow my mind.
And oh, sure it did!
Programming Is (Like) Casting Spells
There’s a reason why Steele and Abelson chose a wizard for the book cover. They make use of a recurring metaphor which is totally accurate: programming is like casting spells. This might seem a bit childish, but it’s a very good analogy if you think it through!
From their point of view, programming is about taking some pre-defined elements (e.g., your built-ins), combine them… and usually giving a name to that new combination. Why? Well, because if you want to access that combination, you need a name for it, right? So does casting spells in any work of fiction where magic is a thing. If you know the name of the spell and follow its rules, you become worthy of wielding its power! That’s why wizards use spellbooks, full of arcane names for spells!
This is so graphic. Your code is your spellbook and you only get access to
parts of code if you know their name. As a linguist this is Semiotics 101: you
can only get so far in a language setting as your lexicon and syntax allows you
to… if you’ve just begun to learn a new language recently, you know the
utter frustrating feeling of lacking the words to say what you wanna say;
your world is effectively smaller as long as you don’t learn the names you
need. Your power in the world is dimished! The same goes for your code: the
more abstractions you know or create, the more powerful
programmer you are!
SICP is very insistent in the need to recognize and abstract away repetitive patterns. Lisp helps a lot as vehicular language in this regard; they’re not even using Lisp macros in SICP, which are a wonderful piece of metaprogramming…1 because they don’t need to. Spot a repetitive pattern? Abstract it away! The course encourages to do so to make your own spellbook as big as possible, full of nuanced procedures that you might want to reuse in the future.
Back then I devoured the book and the lectures. I did mantain some projects in Scheme and Common Lisp back then (on Launchpad!), but I still kept teaching myself C and writing Python or Perl when I needed to automate some task or wanted to write anything without bothering about memory management or low-level issues. The SICP-way of things permeated my code: it gave me a sense of structure, a way to define things, etc. More importantly, it had taught me criteria to take my own decisions on how to design my own code.
Of course, that doesn’t mean my code was any close to good. It was awful. My main mistake was to abuse the bottom-up philosophy SICP wants you to think in. OK, nothing bad in writing code bottom-up, but it’s more natural to do in Lisp than in, say, C: when you write Lisp code, you’re bending the language to what you want it to be… because everything uses the same (lack of) syntax. You can’t tell built-in keywords and user-defined procedures apart. Coding in Lisp can be thought of creating DSLs around a problem you want to solve. Therefore, building from the language up makes a lot of sense, even if it results in procedures that you never get to call… they get optimized away by the virtual machine anyways… In C, though, that usually translated into lots of indirections, unnecessary layers of abstraction, etc.
Programming Is about Computers, Though
Fast forward to… hm… 2018? 2019? I think around those years lots of us became increasingly aware of how harmful bloated software has become, especially everything web-related. I certainly did become more aware and started playing around more minimalist approaches. I also started to look at C and programming from a more machine-centric point of view.
Hey, people change!
I feel the SICP and high-level of abstraction approach is super valid and brings in a very nice set of conceptual tools to the table. But it’s also what has gotten us into massive bloated applications that think it to be totally normal to waste GiB of RAM just sitting there idling. If you pile layers and layers of abstraction, because you want to hide all implementation details and make your code almost a theoretical framework in algorithms… Girl, you’re going to use up lots of resources, I tell ya.
In theory programming is not about computers, yes. In practice, it’s always about computers. You become a way better programmer also by becoming familiar with what’s going on below the level of abstraction of your platform or language of choice!
Small anecdote. One of the reasons why I dislike Python so much is because it makes promises it can’t keep. It wants to sell itself as a totally portable, high-level language, yet its core library includes a commonly used module that has no other option than acknowledge that OSs do things differently… And guess which OSs are at a disadvantage? Those which aren’t POSIX(-like). Why? Because Python is implemented in C… Why? Because it was born within the Linux/FOSS community. There’s no actual solution here, except for parting ways from a POSIX-like interface and create your own… Python wants to feel POSIXy, though… so that’s not going to happen at all. Therefore, even if you’re writing in Python, you should know something about the OS you’re targeting your code for.
Efficiency is not everything, unless you’re dealing with very limited hardware. You’re in charge of how much you want to optimize your code or not… but you need knowledge to make a good, informed decision, don’t you think?
On the other hand, you want your code make sense to humans, starting yourself. That means writing code thinking in terms of abstractions… Have you ever heard or read the advice not to “waste time” writing your own ASM code… because any C compiler will write a better machine code than you would ever do? Write human-readable ASM code and you get performance hits everywhere… because we tend to think in our own cognitive benefit, not in the benefit of the CPU.
As a Sorts of Conclusion?
The book is awesome. I can’t recommend enough. It’s a landmark in CompSci teaching. It’s a personal landmark in my process of becoming the programmer I am today.
I did grow out of its philosophy though. That doesn’t make the book bad, but it does mean that the benefits I see in it now have changed with respect to those early days… And that’s nice. It means I’ve evolved!
In any case, wow what a post. I’m super happy I came across SICP again today. It’s a nice memory in my heart… I wish I have been able to share a piece of that feeling with you, my dearest reader, in this post.
By saying Lisp I’m mudding the waters on purpose here and actually referring to Common Lisp’s macro system, which is simple and powerful because it tries to be as dumbest as possible. Scheme tried to be way too smart in its macro system and failed to deliver… The whole schism between Reports (R6RS vs. R7RS), as the Scheme community calls their specs, is a culture war, not a matter of technology… but with the bad consequence that it makes Scheme quite a bad choice for serious production work unless you lock yourself in a very, very specific implementation. I find this very sad, because the alternative is… Common Lisp? Yes, it is an ANSI standard, so portability is a plus, but it’s a terrible standard. ↩︎