The hard part of computer science is not the programming, and it is not the initial ideas, it is the unshakeable consistency of the application of those ideas, and the way that we stuff these ideas inside each other to make towering layer cakes.

I see this when I teach – it is easy to explain what an

if

statement is and how it works, it is easy to explain

while

, and although

for

is slightly trickier it still isn’t that bad. The difficulty comes when people have to write a program that requires them to put an if statement inside of a loop inside of an if statement. I field questions like Can I put an “if” inside of a “while”? What about a “while” inside of an “if”? all the time. It does no good to explain that you can put anything inside of anything else, because the implications of “anything” and “anything else” are too vast to pick up at first grab.

Similarly, it is easy to explain what an integer or floating point number or string is. And although it is slightly trickier, explaining lists and dictionaries is not too bad either. Explaining arrays of arrays and dictionaries of arrays of dictionaries is where people get lost. It’s this same problem as before – although you may be told that a list can be a list of anything, and that the value stored in a dictionary may be anything, the full implications are hard to understand. Matrices and two dimensional dictionaries and the like are good to know, but they are very hard to understand. The fact that you can make a list of anything, including other lists, is just too much to absorb very quickly.

The next thing that comes up is functions. Functions can contain any code, including calls to other functions. This is crazy for people. They just sort of freak out when they see functions calling each other and nesting inside of each other. They try to hold it all in their head and fail – which is, of course, the whole reason that they broke the problem down into functions in the first place. It’s not just that you have to write a function, it’s that you have to write subfunctions, and subsubfunctions, and so on.

This model of confusingness – that one layer is easy, and multiple layers is hard – serves as a pretty good illustration of why recursion is so unnatural for people. Because if a function can contain any code, including calls to other functions, then it can also contain a call to itself, with references to its own data. And a nauseous ouroborous-esque feeling is the natural response to finding out about this. Recursion is hard to understand and hard to explain, because the whole concept requires a notion of consistency and reliability that is completely alien to our understanding of the physical world.

If we feed a stereo signal through a microphone onto a tape and then play the tape and record it onto another tape, and then repeat this process again and again, then eventually all that gets transferred from tape to tape is an annoying fuzz sound. With computers the information and functions are perfectly reliable, and it is often true that in order to solve a problem we must do the digital equivalent of transferring data from place to place hundreds of times, and often in a weird recursive manner. The fact that this is impossible in the real world and so common as to be beneath notice in computers makes for a few confusing sessions as people attempt to adapt to this new reality.

We stuff data in arrays inside of dictionaries, and then analyze it using nested loops and recursive functions. We do this every day in computer science. Teaching someone to program is a nice illustration of how impossibly weird this activity actually is, and how foreign it is the first time.

Computer programming is strange, and stuffing arrays inside of dictionaries inside of if statements and loops and recursive functions is initially just as unnatural as stuffing a chicken inside a duck inside a turkey. Much like the turducken, though, computer science can yield some tasty results once you go and give it a try.