Structure and Interpretation of Computer Programs (SICP) is considered one of the best books to learn programming. You will find it on different lists. It’s the very first book recommended for self-learning (you can see other options here). And it’s even personally recommended by some “gurus” (Paul Graham, Peter Norvig, etc).
As a newcomer in programming enthusiastic about learning it, I followed the advice. In this post, I will share my personal opinion about SICP and what I learned from it.
A bit about SICP
SICP was the book used for undergrad CS courses at MIT for decades. It was first published in the 80s and I believe it was used at MIT until the mid-2000s. Only recently has it been displaced, at MIT, as the way to learn the fundamentals of CS in favor of a more project-oriented approach based on Python (check the online course here).
After its publication, it created a bit of a revolution in CS teaching. Many universities all over the world included it as part of its curricula. Even today, it’s still studied in universities (you can see an example of one of the best courses adapted from SICP here).
Among other reasons, SICP is very special for the programming language that it uses: Lisp. Not only is it different because of its particular syntax (based on s-expressions), what struck me the most first was that it doesn’t use any for or while loops.
But besides its particular syntax, which is very uniform and concise, there’s something about Lisp that makes you think differently. As someone new to programming, I’m in no position to make this claim. Any programming language is new to me and makes me think differently. But I’m taking the word of other people on this. That is, Lisp makes you think in a way that’s particular to it and that other, more popular, programming languages don’t.
Even before I started reading SICP, I felt intimidated. I had read about it being a very difficult book that only “real programmers” could appreciate. At that time I didn’t know if I had “what it takes to be a programmer”. Or even if I would like it. That’s why I took reading SICP as some sort of “rite of passage”.
Those initial ideas are not important now. But that mindset helped me in being persistent. And that was very helpful because reading SICP took me like 6 months.
Moreover, reading it was hard. I don’t say it to discourage people but it seems to be the kind of book that presents new challenges all the time. It also has some sort of “implicit” presentation of knowledge. For example, while the book uses Lisp as its programming language, there isn’t any extensive presentation of its syntax. You just learn it as different programming concepts are presented, with a few paragraphs in between explaining the necessary bits of syntax. It’s like learning to ride a bike without too much use of training wheels.
This approach has both advantages and disadvantages. Many people criticize SICP for being too unwelcoming for beginners. Using the analogy of the training wheels again, you’re more likely to fall, to become frustrated. You will need perseverance to keep trying, despite falling over and over again. The positive aspect is that, eventually, you will be able to hold your balance. Just like your body gets the feeling of riding a bike, you will gain an understanding of “how it works”. And you will feel good about it.
Now let’s talk about some specific CS related concepts that SICP helped me understand. Overall, SICP offers a very comprehensive understanding of how computers handle programs, from design to machine execution. It starts with very simple programs, introducing new concepts as the complexity or the functionalities of the programs increase. Then it tackles programming as the very art of creating languages to express and solve problems. Finally, it studies how the creation of that programming language can be implemented on a computer machine.
[…] we believe that the essential material to be addressed by a subject at this level […] are the techniques used to control the intellectual complexity of large software systems.Preface to the First Edition
By these techniques, the authors refer to some of the fundamentals of programming. Particularly, to abstraction. This is the main idea behind the creation of functions. It also affects the way we understand problems. Being clever is about knowing “what to see and what not to see” (what to abstract).
As the complexity of programs grows larger and larger, it also becomes harder for any single individual to understand how it works. Some techniques are used to handle that complexity. For instance, we start using older elements as new building blocks.
We do that all the time using functions. While any programming language comes with some “primitives” (functions to add, subtract, etc), we can create new functions and use them in the same way we do with primitives.
We can do likewise with data abstractions or with objects. In a modern programming language like Python, it’s said that “everything is an object”. And the programmer has the capability of creating those objects to his own needs.
I mentioned above that Lisp is very particular for not including neither for nor while loops. The fact is, they’re not needed. Instead of using these loop structures, Lisp will recursively call functions to execute the same statements repeatedly. You can see an example with anonymous procedures here.
As a beginner, recursion was one of the hardest concepts for me. There are some programming languages that don’t even include them. But recursion is at the core of Lisp and SICP.
Here we tackle the question of handling several chunks of data as one unit. SICP introduces a basic way of “gluing” data, of creating compound data structures with Lisp’s pairs.
Most modern languages like Python have a myriad of powerful data structures: list, dictionaries, stacks, queues, etc. The amazing thing about SICP is that all of those more complex data structures are replicated with a single compound data constructor. The basic idea is that “if we know how to glue together two things, we can glue together infinite things.”
Not only that, but we glue things together with “nothing”. I will not say how they do it to avoid spoiling the surprise.
We’re usually presented with the question of “how do we represent data?”. And, as much as possible, SICP says: it doesn’t matter. That’s the idea of data abstraction. With the help of constructors and selectors, you’re able to manipulate data independently of how it’s represented. And when the representation changes, well that’s the only thing that changes.
I remember that the single distinctive notion that I had of programming from high-school and university was variable assignment. It was that peculiar way of using the “equal” sign, so different from mathematics:
x = 1
x = x + 1
I associated the equal sign with equations. But on those expressions it represents assignment. That’s why they are so different.
SICP like the opposite of most introductory courses in this regard. For almost half of the book, you will know nothing about assignment. And when it is finally introduced, they present it as “something dangerous”, even as something bad. Without knowing it, during the first portion of the book, we were dealing with functional programming.
What does this mean? It means that time does not exist. That a function, in our programs, returns always the same result. Just like functions do in mathematics. And while assignment is helpful and necessary under some circumstances, it has its trade-offs.
Is there any way of handling a very large set of data, even an infinite one? Sure, we just analyze it part by part. This is the idea of lazy evaluation. Instead of handling a whole set of values in one go, we divide it into small parts. We analyze what’s needed to proceed and we don’t touch the rest unless it’s necessary.
Before reading SICP, I didn’t know that lazy evaluation was used at the very core of Python. It’s for instance the way iterators are handled. Same for generators, which are more explicit about giving one value at a time and saving the rest for later.
At one point of SICP, they refer to this notion as the “most fundamental idea in programming”:
The evaluator, which determines the meaning of expressions in a programming language, is just another program.Chapter 4. Metalinguistic Abstraction
It refers to understanding programming ultimately as language design. Let’s say we program a mathematics equations solver. We input any expression such as:
x + 2 = 3
And our program returns x = 1. The fact is that what we’re creating is some sort of language. We’re creating a language where we associate symbols to variables, numbers, and mathematical operations. And under the hood, we have also created some expressions that let us handle the elements of our language. That’s programming.
Another example is game development. Consider the Jak and Daxter series. A game is a display of images and sounds, where does this “language creation” comes into play? Well, Jak and Daxter in particular required the development of its own language for its creation: GOAL (which was in turn derived from Lisp).
In its final chapter, SICP introduces a pseudo-machine language to gives us a closer perspective of how a computer handles programs. Low-level details of the implementation of a programming language such as compilation are studied. This new knowledge allows a more complete grasp of the implications of the design of a program and what happens under the hood when we implement them.
Before reading SICP, I was motivated by what people said, that reading it would make you a better programmer. For my part, I can say that I think of programming on different terms now. While I’m programming, I’m more careful of the way I structure my program and I can picture recursive processes more clearly. I have a better feeling of when I should create a new function or when my code is poor.
SICP also introduced me some kind of wonder. Some of their programs are like magic. There are parts of them that are executed almost implicitly. As the consequence of a well-designed structure. If only that, I’m left with the inspiration to create such programs.
There’s something with SICP and magic and its authors liked to play around with the idea of programmers being wizards.
Any sufficiently advanced technology is indistinguishable from magic.Arthur C. Clarke
If you want to study SICP
- The complete book is available for free here. I still recommend getting a physical copy if you have the opportunity. It’s more comfortable, easier to review and SICP is a long read.
- You can find solutions to all of the problems here. There are also many blogs that document it. However, always try solving the problems on your own first and check solutions only to compare with yours or when you’re really stuck. Oftentimes you learn a lot just by struggling until finally you understand what’s going on. But if you never let yourself struggle for a bit, you lose the opportunity of attaining the understanding that comes after it.
- My advice on the problems is to do them on paper before typing them on the computer. Many problems are hard and you’ll be able to focus more on the actual problem solving (instead of syntax, etc) when solving them on paper.
- The StackOverflow and the Reddit communities are great places to ask for help. I found very valuable help on them when I got stuck. Just don’t expect other people to do the work for you. Be sure to properly document your questions and show your previous work.
- As a complement, you can see the authors’ lectures here. They go a bit fast to really understand what’s going on, so be sure to also read the book.
- While I haven’t personally studied them, I have read that the Berkeley’s lectures are a great, modern, approach to SICP.
- In my experience, SICP is a hard book. Don’t feel discouraged if you have a hard time with it. I personally struggled even for days with some of its problems or wasn’t able to solve them. I’ve read of even experienced programmer’s acknowledging the high content density of SICP. So don’t feel bad if you find it difficult. Give it some rest and try again later.
- To someone with no background in programming at all, I’d recommend starting with other resources first.
- Finally, just enjoy it. I took SICP too much as a challenge that I needed to overcome which didn’t let me enjoy it as much.