E48: Multiple metaphors

Download MP3

Welcome to Oddly Influenced, a podcast for people who want to apply ideas from *outside* software *to* software. Episode 48: Multiple metaphors

I’ve done a fair amount of work on metaphor since the last episode, and I’ve discovered two things.

The first is that the non-Johnson author of /Metaphors We Live By/ is pronounced Lake-off instead of Lack-off. Sorry about that.

The second is a bit more consequential: my original plan was to assert that software practice uses metaphors and metaphorical reasoning heavily, so I’d suggest some mental tricks that might help teams use metaphor better. But after having taken a bunch of notes on that topic, and finishing about a third of a script, I more-or-less suddenly realized that we programmers *don’t* really use metaphors. Or we use them in such a narrow way that the theory of conceptual metaphor barely applies to our practice of giving data structures within programs metaphorical names.

I found it too hard to express that in a single episode with a decent narrative flow, so let’s try one regular-length episode and two short ones. Each one will have an interesting fact about the theory of conceptual metaphor, and then a claim that metaphors in programming aren’t like that.

In this episode: nimble switching between metaphor systems, or: how is it life is both a song and a journey?

A warning to non-programming listeners. The last part of the podcast has more unexplained technical detail and jargon than is usual for this podcast. I’ll let you know when that begins so that you can stop listening.

≤ music ≥

There are at least three metaphor systems used in English to talk about the target domain of Argument. By “argument” here, I mean a supported claim, like why my state of Illinois is the best of all US states whose names begin with an “I”. Such arguments are variously metaphorically described as Containers, Buildings, and Journeys.

Understanding why we have three metaphorical systems for one idea means understanding that source domains like Container bring with them a wealth of what I’ll call *associations*. Here are three ways to think about associations:

When a word is brought to mind, other words – associated words – are more easily brought to mind. AND

When a concept is used to solve a problem, other concepts associated with the first are likely to be used in the solution. AND

When one of a brain’s neural networks – that is, one of its self-reinforcing and partly self-regulating collections of neurons – lights up, it will tend to send signals to associated networks that become activated in turn.

These three ways all refer to the same underlying mechanism.

So, let’s take the Container in the metaphor “An Argument is a Container.” What are its associations? There’s that a container contains something; it has content. And bringing content to mind brings further associations: is the content desirable or not? good or not? And experience with things like lifting a box of books or rocks and having the bottom fall out associates containers with the question of whether they’re strong enough for their content, or – more generally – is the container easy to use? Which is a different question when putting content in than when taking it out. Remember that we tend to find containers easier to empty than to fill – I claim there are neurons in the brain that associate the very idea of “container” with that belief.

When you think about containers, that concept’s associations to concepts of content, amount, desirability, strength, and manipulability makes those latter concepts more available to understanding and reasoning.

The metaphor carries those associations from Container over to the concept of Argument. So tight is this connection that it’s hard to even talk about Arguments – perhaps even to think about them – without using the associations from Container. So arguments are about some claim, meaning they have some *content* that’s separate from their *form*, that which contains them. The argument can be good or bad, and it can be strong or weak. We can make judgments about the argument based on how hard it is to *extract* its content. Sloppily-packaged arguments might not be worth our time. And so on.

Now let’s look at a Building. It’s a kind of container, so it inherits – or reinforces – most of the associations of the Container concept. Because a Building is more obviously constructed than the prototypical container, the Building metaphor elaborates on the association between containers and strength: strength is not inherent to a building: it’s *put into it*, so a reference to buildings will tend to light up associations with directed human activities and intentions. Moreover, a building has more structure than just any old container. Buildings have foundations. The higher parts of the building (the better bits, according to the `Good Is Up` metaphor system) rest on – rely on – those foundations.

So the Building metaphor is a better one to choose if you want to emphasize *why* an argument is weak: because it rests on weak foundations, or because more subclaims are piled on than the foundation can support, or because the later (or higher) stages of the argument are constructed too haphazardly to withstand even a breath of skepticism, and so on. We get to say things like this random quote I saw on Mastodon:

“His *underlying premises* were faulty, and every argument *built on* that jenga tower was equally fallacious.“ [My emphasis]

When we add the Building metaphor system to our repertoire, we learn more about how to think about arguments. Alternately, we learn how people around us *already* think about arguments, and we learn to think like them.

Because a building is *built*, constructed over time, there’s also an association to *progression* or *progress* that can be used when talking about arguments. But when you *really* want to talk about (or think about) progress, you reach for the Journey metaphor.

The concept of Journey is associated with ideas about changing terrain, and those associations carry over to arguments. To finish a journey, you have to cover all the ground in between; similarly, you don’t want an argument that “skips some steps.” A journey can be direct or circuitous, as can arguments. When you tell someone their argument has “lost you,” as if it were a guide through the forest, you’re in a sense providing them with associations to ready-made, metaphorically-justified fixes: the argument can take a different path that might be easier for you. Or your interlocutor can smooth out some of the rough bits, or make a diversion around a sticking point. Maybe they should retrace their steps back to the point of confusion. And so on.

That explains why intermixing metaphors is fine. Here’s an example I made up for the end of a chapter in an imaginary math book:

“Let’s summarize how far we’ve *gotten*. After *going down* a few blind alleys to provide motivation, we’ve arrived at the axioms that will serve as the *foundation* for the rest of the book.”

In this, I’ve used a Journey metaphor for its associations to progress and a Building metaphor for the associations to well-constructed strength. The complete metaphors don’t have to be consistent; the associations just have to work well together for our purposes.

≤ short music ≥

Use of multiple metaphors for a target domain is rare in software. I can think of two examples.

The first is the humble machine word used as an integer. If I remember right, sometime in 1975 was the first time I declared an integer variable. That was in Fortran, for an IBM 360, so the metaphorical correspondence was `A 32-Bit Machine Word Is an Integer`.

Actually, I want to make a distinction between the abstract concept “Integer” and the *experiential* concept of “Counting Number.” That’s because Lakoff and Johnson claim all metaphors are based on experience in the physical and social world, either direct or vicarious. (That last means we learn from other people’s experiences, as told to us.)

I’m going to assume that children still learn to count on their fingers, and that what they do is count things like the cookies or marbles sitting before them. Thus addition and subtraction are well understood early in life, which makes it easy to map the source domain of counting numbers onto the target domain of machine words. Adding and subtracting, for example, map directly from how those operations work with counting numbers.

Division is also easy. A child used to counting cookies and marbles has no trouble dividing five cookies among two people. What’s fair – and humans, like other primates, have a strong sense of fairness – is for each person to get two whole cookies and half of the remaining one. When it’s marbles, which are indivisible, things get more complicated. Each child will get two, but what happens to the extra is a matter of social negotiation, perhaps one in which two cats-eye marbles are worth three of the more common ones. That’s the sort of thing we did at Harvard Park Elementary School, my alma mater.

I mention this because when integer division is taught to fledgling programmers, it’s treated as a weird thing that five divided by two is two (in Fortran in 1975, at least). But is it weird? It’s just like dividing marbles, with the exception that you can’t dicker over who gets the extra one. Instead, I guess, the computer just takes it.

Integer division might be weird if all your experience is with calculators, where there are no counting numbers, not even any fractions, but just floating point numbers. But I think not many people skip learning with their fingers: “one potato, two potato, three potato, four.”

However, a big difference between machine words and counting numbers is that
counting numbers have no biggest element. You can always add one to a number and get a bigger number. That isn’t true of machine words, where you might end up adding one to a very large positive number and get a very negative number. This makes absolutely no sense unless you understand in some detail how computers work.

That difference mattered in 1975, when an advanced computer could only count up to a few billion. It mattered even more with the computer I started working on in 1981, where you had to take explicit measures to be able to count to more than a few tens of thousands. Nowadays, the upper bound of a machine word is so high you have to do something outlandish to breach it, like count the number of atoms in the universe.

The problem we have is that the metaphorical system “a Machine Word Is a Counting Number” simply has no place for an association to “unless you try to count too high.” There’s no mapping from the source domain of counting numbers to that special fact of overflow in the target domain of machine words.

But there *is* an alternative metaphor available: the metaphor `A Machine Word Is a Container.` We all have experience filling – and overfilling – containers, so reminding us to think of a machine word as a container for integers could remind us to worry about what we literally call integer overflow.

Together, the source domains of Counting Number and Container allow us to think about machine words better than do either of them alone.

Now, given our profession’s not-so-stellar success at avoiding overflow bugs, it would seem that the Container metaphor didn’t do much good. I speculate that’s because it didn’t get *used*. By analogy, if you’re discussing the validity of an argument and use only Journey metaphors, you can’t expect your listener to automatically think about the strength of the argument, because those associations aren’t attached to the Journey source domain. So if you just declare the variable as an integer, and use only arithmetic or Counting Number operators on it, why would you think of the variable as a container of integers that might overflow?

Some languages let you declare integers as things like a “uint32”, but that’s invoking yet a third source domain: that of a machine word as a lineup of 32 bits in order. That evokes associations of doing things to individual or subgroups of bits, like flipping them, but it doesn’t contain – I think – any association to *arithmetic* overflow, though you can have bits “fall off the end” if you shift them, an association that doesn’t exist in the earlier two metaphor systems.

A metaphor can’t aid in understanding if you don’t use it. I speculate that if all integers had to be declared as “bounded integer”, overflow errors would have happened less because the programmer would have been reminded of overflow. Except, of course, that everyone would tweak their editor so that it auto-expanded typing `i-n-t-space` to “bounded integer,” allowing them to save precious keystrokes at the expense of never having boundedness brought to mind.

≤ short music ≥

My other example is what used to be called a “system metaphor.” That’s a metaphor applied to an entire application that refers to its structure. It’s useful when deciding where to put code and how it should hook into other code. The classic example is from an old payroll system. The governing metaphor was of an assembly line. In effect, paychecks would start at the beginning, moving from one quote-unquote “station” to another, where the results of another bit of computation (specific to that paycheck) would be bolted onto it.

System metaphors never really caught on, and I think their usefulness in thinking about structure went away as everyone started using pre-packaged frameworks. If you use web application frameworks like Ruby’s Rails or Elixir’s Phoenix, they already tell you where to put things and how things hook together. You don’t need a metaphor. (Alternately, you could just say “Our system metaphor is Rails.”

I did, however, once encounter a system that used two system metaphors simultaneously. They were “The Vat” and “A Cruise Ship.” The “Vat” metaphor built off the old philosophical chestnut “How do you know you’re not just a brain in a vat?” That is, you *think* you have a body that’s responding to an outside world, but maybe you’re just a brain bathed in nutrient fluid, sitting in a vat (with glass sides, of course), connected by cables to a computer that feeds you signals that only seem to come from the real world. How would you know?

As an aside, you actually *are* a brain in a vat. As neuropsychologist Lisa Feldman Barrett puts it, quote “For your entire life, your brain is entombed in a dark, silent box (i.e. a skull).” That skull has to figure out what’s going on in the outside world, and in the rest of your body, from signals coming into it via those cables we call neurons.

Because this was a system whose creators were a bit obsessive about security, the Vat metaphor emphasized that user-provided code had no access to anything except via the highly-regulated official interface. (No fair reading directly from disk!) Nowadays, we call this sandboxing.

The Cruise Ship metaphor I remember less clearly – it’s been close on 30 years. It was mostly about defining three kinds of objects in the system, labeled Passengers, Crew, and Stewards. All communication between Passengers and Crew was mediated by the Stewards. The metaphor was the Passengers never see the people actually running the ship/system. That is, they see only Stewards, never Crew.

That one bugged me because it reversed the inside-outness of the Vat metaphor. Code that was *inside* the Vat was *outside* the cruise ship. It can’t be both! But, as we’ve seen, our brains are fine with inconsistent metaphors, so I in my capacity of Judge of All Architectures rule those two metaphors fine.

≤ short music ≥

If you’re not a programmer, it’s probably wise to stop listening now.

The main use of metaphor in programming is the creation of explicit, in-program names for data structures. Things like Invoice, User, Reservation, or Organization. These are metaphorical in the sense that the thing you name `Invoice` isn’t in fact an invoice but a pile of machine words whose properties are intended to map on to the properties of real invoices, including the associations they have (like that an invoice must be paid by a particular date). So we have the familiar source- and target-domain structure.

However, we’re *generally* missing the multiple-metaphors-for-one-concept structure of true conceptual metaphors, which deprives us of the power to say (in a metaphorical way) everything we might want to say. We’re stuck doing the equivalent of talking about written or oral arguments using *only* the Container metaphor, making it hard to think about topics like whether an argument is well supported or proceeds smoothly from its premises to its conclusions.

Now, you might say that’s fine. We can say things literally, not metaphorically. For example, I might critique an argument with “if you were to try to restructure this argument as a list of claims, where each claim is the logical consequence of some set of earlier claims, you would discover that some necessary claims are either missing or the logic doesn’t work.” And that’s just the sort of persnickety literalism that we’re used to in programming, so what’s the problem?

No problem at all, really. But we’re doing something different – a different kind of communication, a different kind of reasoning – than what Lakoff and Johnson talk about. And you will have foregone some of the inspiration-sparking power of generative metaphor. Recall Schön’s example of someone saying “A paintbrush is a kind of pump,” thus adding the associations of Pump to those of Brush. That’s not to say Schön’s researchers couldn’t have realized that the negative space between the paint brush bristles is more important than the bristles themselves. But – if Lakoff and Johnson are right about what the brain does with metaphors – the realization will have to come from somewhere else, from first principles, without the crutch of already having a bunch of associations about Pumps that can be transferred to Brush.

Alternately, you might argue that lots of structures have multiple names. After all, a classic example when teaching object-oriented programming is to have a more-abstract class named `Vehicle` and a more-concrete class named `Car`.

I concede that “it’s a vehicle or is it a car?” has some of the same… texture as “it’s a Building or is it a Journey?” Just as a Building can add new associations to an argument thought of as a Container, a Car class adds new properties, methods, or associations to a Vehicle class.

However, the way subclasses are *generally* used differs. If you think of code as the way we talk to the computer – and other programmers – we’re usually talking about *either* the superclass (Vehicle) or the subclass (Car), not both at the same time.

Consider a Java method that takes an argument of type `Vehicle`. The whole *point* of declaring it so is that we’re not supposed to use anything specific to `Car` in that code. Indeed, doing so with a runtime check is generally considered a design smell.

Similarly, if we’re taking an argument declared to be of type `Car`, we’re generally indifferent to whether a method we’re using is defined up in `Vehicle` or in the `Car` subclass. That is, we not in a situation equivalent to realizing, “Hey! This car is a `Vehicle`, so I will think of it in a different way that gives me a bunch of new abilities.” That can only be true if something about Cars falsifies a true fact about Vehicles. It’s generally considered dodgy to do that in programming. But it’s doing that with pairs of conceptual metaphors that gives those metaphors their *oomph* for reasoning.

One type of inheritance that feels a little bit more like natural-language use of conceptual metaphor is when you sneakily have, say, the `Invoice` class inherit from the `List` class – not because an Invoice is, conceptually, any kind of a list but because there are a couple of List methods that would be handy to use. Classic inheritance of implementation, and it does feel a bit like natural-language metaphor in a “who would have guessed this paintbrush is also a pump” sort of way. But such inheritance is also considered bad style.

Inheritance is out of fashion these days in object-oriented languages, where many march under the banner of “prefer composition to inheritance”. So the core relationship changes from X is_a Y to X has_a Y. You’re no longer using two names – X and Y – to refer to a single object or data structure. You’re using the names to refer to two objects, one of which a part of the other. So an Invoice might *have* a list of goods, but it isn’t a *kind* of list of goods.

There’s a figure of speech, synecdoche, that fits this situation. Synecdoche is when a part of something is used to refer to the whole thing. Examples:

“I’ve got a new set of wheels” when referring to a new car, or
“We need some new blood in the organization,” or
“There are a lot of good brains at that university.”

Lakoff and Johnson point out that a synecdoche does more than just point to something; it also signals which of the many associations you might have for the whole are relevant right now. For example, “good brains” signals why you’re talking about people at the university: the need for intelligence is our topic. “A new set of wheels” focuses on the associations of wheels, which for the classic American teenager includes greater freedom of movement, which stands in for greater freedom from parental and adult control. “New blood in the organization” alludes to blood as the life force – just as vampires replace stale blood from their last meal with vital new blood, organizations replace tired-out employees with fresh ones. “Fresh meat” is perhaps the more telling metaphor for employees most of the time.

I can see this working for composite structures in programs. For example, casually referring to an `Invoice` object as the item list might help focus conversation between two people who are pair-programming. If you’re writing some routine that is only about the list-like aspects of an `Invoice` object, maybe naming the variable that points to it `item_list` might help the reader of the code, though it creeps me out, personally.

Usually, though, I think most programmers would think something’s off if they have to know about a data structure’s innards to use it.

≤ short music ≥

So, my summary is that names in programs are kinda-sorta metaphorical but mostly not. Mostly they are just names. In common terminology, they’re “dead metaphors,” ones that serve only as a key into a hash table of concepts. Which is not a bad thing! But insisting such metaphors are consequential is like insisting that the sound of the word “cow” is somehow intrinsically linked to the properties of a cow – that “cow” isn’t an arbitrary sound-collection, but the *right* sound-collection for that concept. People used to believe that; part of the reason foreigners were barbarians is because they stubbornly used the wrong words for things.

To my mind, metaphors are most interesting when they involve *surprise*, when they jolt you out of your usual thinking. Things like “a paint brush is a pump” do that. So do literary or creative metaphors like Emily Dickinson’s extended metaphor in her poem “Because I Could Not Stop for Death,” which starts:

Because I could not stop for Death –
He kindly stopped for me –
The Carriage held but just Ourselves –
And Immortality.

She’s playing with the age-old trope of personifying death, but making death a kindly, helpful gentleman. Which is a different way of looking at death.

At this point, I might put metaphor to bed and move on to the next topic. But I think I’ll ask your indulgence to explore two other aspects of metaphor that also mean metaphor is not what we in programming do. Those are: levels of abstraction, and metaphors don’t live alone.

Thank you for listening.

E48: Multiple metaphors
Broadcast by