27 July 2016

Once upon a time, when I was growing up, I was in a class where we were given the following task.

Write down instructions for how to make a peanut butter and jelly sandwich.

If you haven't done this before, it might be interesting for you to go ahead and try to write down instructions. Once the instructions are written, here's the followup task.

Follow the instructions, and see what kind of results you can get that are as far as possible from your typical idea of a peanut butter and jelly sandwich.

With a class of multiple students, it probably works better to have them swap their set of instructions for someone else's, since that makes it easier to switch into the mindset of interpreting things in unintended ways. If you wrote down your own instructions, here are some possible unintended results.

  • Could the bread end up between the peanut butter and jelly instead of the other way around?
  • Could the knife you use to spread the peanut butter and jelly end up inside the sandwich?
  • Could the instruction follower have failed to acquire peanut butter because the jar was closed?
  • Could the peanut butter jar be left open at the end?
  • Could the pieces of bread end up facing different directions (and do you care)?
  • Could the peanut butter and jelly end up along the border of the bread rather than what we usually call a "side"?

The purpose of the exercise was to illustrate that instructing a computer can be similar to instructing a human that follows your directions, but in ways that you didn't expect or intend. In order to get the results you want, you need to make sure your instructions are clear and precise.

The analogy isn't perfect by any means. Natural language has ambiguity all over the place. Hardly a single word can be said without some possibility for misinterpretation. On the other hand, programming languages generally have an unambiguous vocabulary and grammar. The problem is that someone learning programming for the first time has no experience with building up instructions for a complex task out of those kinds of simple components.

This exercise uses computing as motivation, but no computers are actually involved. It's fundamentally an exercise about communication, and coding happens to be another form of communication that has some similarities. In order to communicate in this sort of environment, you need to be able to specify exactly what you mean. Moreover, you need to have something precise that you mean in the first place.

When you get down to it, coding really is a form of communication. But what you might not get from the sandwich exercise is that the computer isn't the only thing that needs to be able to understand the instructions. Imagine instructions that contained steps like "Apply a force of 0.1 newton in the direction opposite gravity for 0.3 seconds." You could conceivably create such a set of instructions that makes a perfect peanut butter and jelly sandwich. But if someone looks at your instructions, are they going to understand what it means? Are they going to be able to modify it to make a sandwich with something else in place of the peanut butter?

In the end, code is for both humans and computers. You can find people who say that it's primarily for humans or primarily for computers, but the exact importance ratio isn't what I care about. You'll find that most programmers dislike writing code in assembly or machine code, because it's difficult to write assembly that's good for humans, despite how easy it is for computers to understand. Instead, we've built up abstractions that allow us to write code in other languages that are easier for humans to understand, while having a well-defined translation into machine code, meaning that we can write for both audiences.

Mathematics is actually similar in that regard. Usually the consumer of a mathematical paper is a human, but you could imagine wanting a proof in the formal sense, being a chain of statements where each statement is derived by applying some axiom (say from ZFC) to previous statements. In that sense, math papers are also written with two audiences in mind: the humans trying to understand the idea of a proof and the axiom purist that wants to be convinced that a statement is true. In practice, axiom purists are rare, and the humans are merely interested that such a purist could be convinced after some straightforward but potentially tedious translation of the proof.

There's been a lot said about whether we should teach every student how to code. From my perspective, coding shouldn't be the end goal, but it's potentially a great way to introduce people to a new environment where the preferred method of communication isn't what they're used to.