Metaphors: Bridges and Barriers
Author: Joel Neely
- Introductions and aphorisms
- Switching hemispheres
- Cooking a program
- The corporate office
- Back to the toolshed
Introductions and aphorisms
One of my favorite sayings is
You can only learn that which you already almost know.
(unfortunately I don't know the origin of this jewel). As someone who has played the roles of student, teacher, and sometimes mentor for more than all of my professional life, I have witnessed the truth of this statement first-, second-, and third-hand. It is a cousin to the more down-to-earth and familiar
To a small boy with a hammer, everything looks like a nail.
Years ago, these thoughts inspired me to another saying
A tool is an instrument for limiting the types of work you can perform.
which I claim as Neely's Fourth Law of Systems. (Someday I'll document them all; there are six as of this writing.)
These statements are just as true of our work as programmers as of any other craft, although our raw materials and tools (as in our sister trades of Mathematics and Logic) are thoughts and ideas, rather than iron and anvil or wood and lathe. Metaphor is such a pervasive tool in programming that we often forget that we are using it. Taken too literally or rigidly, a metaphor can end up setting boundaries on our thinking rather than helping us reach new ideas.
Programming is hard enough without adding problems of our own making. Sharpening (or outright replacing) an ineffective tool can help eliminate self-imposed limits. This little essay looks at two cases of this point, one as a semi-serious warm-up and the other as a completely serious look at programming.
Considerable ink has been consumed (or spilt!) over the idea that the left and right hemispheres of the brain perform different kinds of processing. Some writers pose exercises to help the reader "switch hemispheres" to get a new perspective on their work. Let's apply another kind of hemisphere-switching to get a new perspective on a sample problem.
Here's a small story of the kind we encountered (or dreaded) in school:
Billy and Susy were on the farm, looking through the fence at a
collection of pigs and chickens. After staring thoughtfully for a
few moments, they turned and walked toward the house. Billy said,
"I counted 12 animals, but I don't remember how many were pigs and
how many were chickens." Suzy replied, "I counted 32 legs, but I
don't remember how many pigs or chickens there were either."
Can you help Billy and Suzy figure out how many pigs and chickens
Since I'm writing this to a bunch of programmers, I'll bet we all can immediately "see" this as a simple case of two equations in two unknowns, and can solve it easily.
p + c = 12 -> p = 12 - c
4p + 2c = 32 -> 2p + c = 16
Therefore, 2(12 - c) + c = 16
-> 24 - 2c + c = 16
-> 24 - c = 16
-> 8 = c
Therefore, p = 4
or something similar.
Since I'm writing this to a bunch of programmers, I'll bet we all can immediately "see" this as a simple case of generate-and-test, and can solve it easily.
solve-animals: func [
type1 [string!] legs1 [integer!]
type2 [string!] legs2 [integer!]
totanimals [integer!] totlegs [integer!]
for n1 0 totanimals 1 [
n2: totanimals - n1
if (legs1 * n1) + (legs2 * n2) = totlegs [
n1 type1 "and"
n2 type2 "gives"
totanimals "animals with"
print "No solution!"
>> solve-animals "pigs" 4 "chickens" 2 12 32
4 pigs and 8 chickens gives 12 animals with 32 legs
or something similar.
Now, let's switch hemispheres and try again.
With apologies to my friends down under for any accidental mangling of language or zoology...
Ian and Sheila were on the station, looking through the fence at a
collection of 'roos and emus. After staring thoughtfully for a
few moments, they turned and walked toward the house. Ian said,
"I counted 12 animals, but I don't remember how many were 'roos
and how many were emus." Sheila said, "I counted 32 legs, but I
don't remember how many 'roos or emus there were either."
Can you help Ian and Sheila figure out how many 'roos and emus
Whereupon a grizzled but lovable figure replies...
Since 'roos stand on their hind legs, the 12 animals would be
standing on 24 of the 32 legs, leaving 8 legs in the air, which
would belong to the 4 'roos, leaving 8 emus.
and then goes walkabout, or something equally inscrutable to us left-brained northern hemisphere dwellers.
Stories like this are often dismissed as jokes or parlor tricks, of little interest because they don't "scale up" or generalize to other/bigger problems. Actually, they do, but that's left as an exercise...
The main point of telling this little story here, other than the fact that I like it, is that it shows how a shift in perspective can drastically change the effort of solving a problem. Now, let's get serious about programming.
Cooking a program
When I first learned to program, there was a metaphor commonly used to explain what programs are and how programs are performed. When I began teaching (I'm now ashamed to say) I inflicted this same metaphor on my students.
I now believe it to be thoroughly wrong; this article is my public apology and retraction.
Cookbook and cook
The metaphor asserts that a computer program is like a cookbook.
A cookbook typically contains multiple recipes, each with its
own ingredients and instructions. Some of the recipes are for
frequently-used operations, such as "separating eggs", "making
a roux", or "beating egg whites until stiff". While cooking a
recipe, you keep track of your place with your finger. When the
recipe calls for you to perform one of the other recipes, you
leave your finger marking your place in the original recipe, turn
to the other one, work through it and then return to where your
finger is marking the place in the first one.
Then, this figure is applied to programs.
A program typically contains multiple functions, each with its
own data and instructions. Some of the functions are for
frequently-used operations, such as "calculating sales tax",
"plotting a bar chart", or "calculating the average of a
collection of numbers". While running a program, the computer
keeps track of its place. When the program calls one of the
functions, it marks its place in the original program, runs the
function, and then return to the place previously marked.
What's wrong with this picture?
Humans can do some things much easier than computers can, and vice versa. By identifying the student (as a cook making a recipe) with the computer (running a program), this subtly prepares us for confusion over what is easy and what is hard. For example, all of these misunderstandings have followed from this metaphor:
- "I only have two hands, and need at least one free to do any useful work in the kitchen. What happens if the second recipe calls for another? How many fingers (and hands) can I use to mark places to which I must return?" I have actually heard students ask whether one function can call another, and express confusion over the idea of "nested function calls" as a different concept from "simple function calls".
- "There's only one of me, and I can only do one thing at a time. I get confused if I have to deal with constant interruptions or try to switch my attention back and forth among different activities." By discarding the layers of abstraction between low-level hardware and high-level languages, the metaphor pushes us to address implementation details of multi-tasking/-threading before the student is ready for them. Yet daily life is full of things we use without concern for the inner workings: televisions, calculators, telephones, automatic transmissions, and so on.
- "If I have one finger marking my place on a page, and I end up back on the same page, how do I know whether to start over or go back to where my finger is?" Recursion is simply too fundamental a concept in programming for us to mislead students (or ourselves) into thinking of it as hard or "advanced". Doing so is poor teaching, bordering on criminal negligence.
- "All of the recipes have to be in one cookbook, right?" This metaphor invites inferences about how programs are packaged and deployed. It implies that a statically-linked program is somehow simpler than one which uses dynamic libraries, RPC, functions generated a run-time, etc.
I could go on, but I hope those examples are enough to expose this metaphor as fatally flawed. It's time for a better tool.
The corporate office
Most of us have some concept of working in a big organization, even if our experience is limited to television and the movies, instead of first-hand knowledge. Let's use that setting as the basis of a replacement metaphor.
The personnel pool
This metaphor asserts that a program is a job description; running programs are described as the activity of workers in a modern office building.
Each worker in the office building has a job description that
specifies the work to be done. Some of these job descriptions
call for other jobs to be performed. When that happens, the
worker phones the personnel department and identifies that new
subordinate job. The personnel department sends a worker from
the personnel pool, who comes already equipped with a photocopy
of the job description. The original worker gives the new
assistant any information required by the assistant's job
description, and they cooperate to get their work done.
Let me interrupt this little story to point out that we can now explain several important ideas in computing by making small changes in the way that the way that the original worker and the assistant cooperate.
Let's imagine some things the worker could say to the assistant.
- "I'm going to take a nap. When you have finished, wake me up, give me the result; then you can go back to personnel." This is a standard function call.
- "I see that your job description looks just like mine. Here's your share of the stuff I'm working on." This is recursion, and it is almost not worth pointing out as a special case.
- "I'm going to keep working. When you have finished, get my attention and give me the result; then you can go back to personnel." This is multi-tasking with signals.
- "I'm going to keep working. As you produce each result, put it in my in-basket." This is multi-tasking with a message queue.
- "Make a copy of anything you need from my desk, then you can find a free desk and continue working." This is the classic Unix-style "fork and exec".
- "Do the blah-blah-blah part of the job description and give me the result. Then hang on to your notes and wait for me to give you another assignment from your current job description." This is OOP, with the new assistant now behaving as an object.
- "When you have finished, give the result to Pat over at that desk, and say it's from me." This is delegation.
- "Here's the rest of my job description. When you have finished, call personnel and hand over your results and the rest of my job description to the person they send up. I'm going back to personnel myself." This is continuation passing.
Notice that we've made no assumptions about where/how the personnel department located the job description for the new assistant. They could have done this in many ways.
- It could have come from the same file/manual as the original worker's job description. This is static linking.
- It could have come from a company policy manual. This is a case of using a shared library.
- They could have had it faxed to them as needed. This is a case of using a dynamically loaded library.
Now, suppose the new assistant phones in, rather than showing up in person. (We don't care whether the phone call comes from another extension in the same building, or another building in the same town, or is a long-distance call from Erehwon.) The conversation could proceed in many ways, including these:
- "Here's the information you need... Now I'm going to take a nap. When you call me back with the result, the phone will wake me up." This is RPC (remote procedure call).
- "Here's the information you need now... When you get through with the first part, call me back and we'll talk about what to do next." This is client-server computing (including the specific case of remote objects).
- "Hello, directory assistance? Can you get a pizza parlor on the line for me?" The employee is now using an ORB (object request broker).
I'm sure that you can supply additional cases of your own.
Back to the toolshed
I believe that this metaphor is a great improvement, both in terms of simplicity and in the range of things that can be understood as simple variations on a familiar theme. After all
It's a poor workman that blames his tools.
It's a poor carpenter who keeps using a dull saw.
especially if he's trying to drive a nail!