Embodied Logic: Observations on the Act of Programming
What is programming? What kind of language is it? What’s at play in the activity or (as Vilém Flusser would put it [1]) the gesture of programming? Insofar as the act of programming did not even exist until not long ago and is now essential to keeping almost all aspects of society working, these questions might well help us understand the times we live in.
Let’s not rush to answer them. Let’s not act as if we already knew: on the contrary, let’s approach them carefully, and begin by observing the programmer at work from a certain distance. What does she do? What is her attitude, her stance? She is probably sitting at a desk, in front of a monitor, with her hands on the keyboard. At times she types something; at others she appears absorbed by what she is reading or seeing on the screen; at others still she may be silent and unmoving, gazing out the window or up at the ceiling. Every so often she moves the mouse or a finger on the track pad and clicks a few times.
So far, she doesn’t look much different from someone writing an email, a report for work, or a paper for the university. She doesn’t even stray too far from pre-digital activities, like typewriting. But if we lean in just a bit closer, close enough to look over her shoulder at her screen, we can see that the text she is writing is quite peculiar. It is not a block of text, but it is broken into mostly short lines, in a way reminiscent of poetry. Looking even closer, however, we see that, in between what seem like words in English, there are numbers, arithmetic and logical operators, parentheses, brackets, and other odd characters. It looks like an absurd mix of writing and mathematics, adrift somewhere in between saying something and making calculations, but failing to do either.
We can safely assume that this is some kind of language. Indeed, it must be a code, that is, an artificial language created with a specific purpose in mind. What might that purpose be? Here lies the first major difference between the programmer and the one who, in similar situation, writes an email or report. To indulge in a quick, commonsensical generalization, we can say that the function of language is communication. We write something to say something to a specific person (as in a letter), or to a broader audience (as in an article). Sometimes we even address some deferred version of ourselves (as in a shopping list or a diary). But the programmer is not addressing some other one, nor others, nor herself. Programming is her way of communicating with the computer.
There is something odd there. The very idea of communication seems to entail a certain symmetry. The sender and receiver of a message are alike in some important ways: both understand the language used to convey the message, which is how they can confer it with meaning. The receiver can, potentially at least, answer. But the computer is not a person; it does not comprehend what is being said, and it cannot answer — at least not using the same code. Programming is an intrinsically unidirectional language. If there is any communication happening there, it is an asymmetric sort, with two radically different entities at each end.
Now we can perhaps begin to figure out the blend of text and calculation we saw on the screen. It is an intermediate code, with something machine-like and something human-like about it. Computers do not speak natural languages (yet), and we can’t make sense of the binary data that goes in and out of the processor. High-level programming languages are a compromise, a halfway territory where, with some effort on the part of each, two very different beings can meet.
It might seem curious that computers — human inventions — “think” so differently from us. Why didn’t we create them in our own likeness, like any decent god would? Maybe because there was never an act of creation. Computers evolved gradually from machines, and their machine-like behavior does not reflect the full spectrum of human capabilities, but only one of our mind’s “specialties”: the ability for logic and calculation. Computers are formal machines: they carry out symbolic manipulations devoid of any content with great efficiency.
Now that we share every day of our lives with them, this essential distance creates all kinds of problems, which are ultimately problems of translation, of effective communication with an Other. For example, there is a digital gap between those who “speak the language of machines” and those who don’t, creating a new form of power for the former and a new type of illiteracy for the latter. Those who don’t understand computers, who have trouble even using a social network or paying a bill online, are the outcasts under this new regime. For them, computers are as threatening and baffling as an alien invasion.
“Interface design” is the name of the discipline that sees to making the apparatuses and systems we deal with every day accessible. Its task is, essentially, to simplify computers’ inherent complexity into a smooth, “intuitive” surface. One side effect of the effort to give machines a “human face” is turning them into black boxes, magical objects impenetrable and mysterious in their internal logic. Users are confined to a position of passive acceptance of whatever the device does, and a freedom restricted to the few options the interface offers them. They become a sort of function of the device’s program [2].
We programmers, on the other hand, are faced with a blank screen. The computer is before us, under our fingers, like a willing and waiting creature. Possibilities are unlimited. Before writing a single line, we must make a number of decisions about possible tools and strategies to tackle our task. We may have a general idea of what we want, but to carry it out we have to make it precise, break it into parts, unfold it into logical steps. These are crucial requisites to explain it to the machine. We often include, remix, or modify existing code, whether made by others or ourselves. In any case, we must think about the problem by putting ourselves, so to speak, in the place of the computer.
We don’t find that burdensome or unnatural. On the contrary, therein lies the enjoyment of programming. We revel in the demand for formal rigor. We are captivated by the game. For the program to run or compile, for the machine to understand (in its non-human way of “understanding”), we need to embody its absolute inability to engage ambiguity or interpretation, its rejection of all inconsistency, its overwhelming literalness. Understanding these restrictions is the key to gaining access to the power of the tool we have in our hands. If someday computers become truly intelligent, and we can communicate with them in a natural language like English or Spanish — chat with them as we chat with a neighbor — we programmers would undoubtedly mourn the loss of that wonderful stupidity.
So, let’s get back to the question: What kind of language is programming? Almost a century ago, linguist Karl Bühler distinguished three functions of language: the representative, which expresses states of real or imaginary things; the expressive, which manifests the speaker’s feelings or subjective states; and the appellative, which conditions or modifies the receiver’s behavior [3]. A program is not representative (it is not true or false, though it deals in truth and falsehood) and it is not expressive (it is not a manifestation of feelings, though it can be appreciated as an aesthetic object). Perhaps it is, then, appellative (or imperative), since it consists of a set of instructions that are going to be processed by the computer. In that case, the criterion for success is not the truth or beauty of the program, but rather the extent to which the machine does what we want it to do.
Those of us dedicated to creative programming (so-called: isn’t any kind of programming creative?) also relate to language’s expressive function: we write code to generate art (visual, sound, text-based, interactive…). We communicate with the machine to communicate very personal ideas, intuitions, or feelings to others. It is a curious detour. What pushes us to use programming as a creative tool? Why resort to a formal and abstract procedure to express ourselves? Why do put ourselves in the strange situation of giving orders to make poetry?
It might prove certainly difficult to answer those questions unless we note first that programming doesn’t feel like giving orders. Pushing buttons and turning cranks on an industrial machine was probably more of an imperative activity, but reducing programming to the language’s appellative function seems like a careless simplification: the computer is much more than an artificial slave. To program is to design information flows, to project dynamic systems, to invent the rules of a game. It is more like creating a machine than operating it. Only the most trivial programs are perfectly predictable: any algorithm that is minimally complex becomes a land to explore, a source of surprises, and an object of investigation. Rather than giving orders, to deal with the computer feels like performing a series of experiments, like a process full of comings and goings, dead-ends and unexpected findings. We rarely end up where we thought we would. The computer does not respond in code, but whatever it does when the program runs is a sort of answer. Something very similar to a dialogue is established, and initiative and creativity can come from either side as it is unfolding.
What we need, it seems, is a language function that Bühler did not consider (nor did Roman Jakobson, for that matter, when he expanded the number of functions to six [4]). It is the kind of language used in the rules of a game, or the axioms of a formal system. Could we call it, perhaps, a regulative function? It is certainly not about giving orders. Statements of this sort do establish restrictions, but they also open up possibilities, create systems, set up small artificial worlds. In other words, they generate forms of freedom. (Indeed, we might well wonder whether freedom is conceivable at all without the framework of a system of rules of some kind.)
We artist-programmers are interested in the aesthetic potential of these systems: in everything the ultra-fast symbolic manipulation of the machine makes possible, in what could not be done without it. In some ways we are like composers: they too use a formal system (music) to produce a code (the score) that someone else executes (the player). The key difference lies in the fact that the program can yield a different result each time it runs, or even vary in unpredictable directions while it is running in response to internal or external variables. We resort to various means in order to find the most interesting zones of tension between regularity and disorder, using — for example — randomness, interactivity, external information sources or complex systems.
Writing is usually linear: whereas images present us with a multiplicity of information at the same time, text (and speech) may return to previous subjects or anticipate what comes next, but ultimately it progresses one word at a time, on a single thread extending from the beginning to the end. Programming is strange in this regard too, because hidden in the code there is a program flow that goes round and round in loops, splits in conditionals, enters and exits functions, and does even run simultaneously in parallel channels [5]. The programmer must imagine, as she writes, a trajectory that will only become real at the moment of execution; she must be aware of where she is at all times, and avoid getting lost in that garden of forking paths. Let’s then append this characteristic to the list of our observations. Programming is, in short, an asymmetric, formal, executable, regulative, and non-linear language.
If, after all these musings, we return to the scene at the beginning, we may find it bathed in a different light: perhaps the difference between the two characters in it is not so cut and dry, and we may even think of them as two parts of a kind of hybrid organism, or as locked in symbiosis. Something is happening that neither one nor the other could do on their own. The formal capacity of the machine is enmeshed in human sensitivity, and abstraction exists alongside a series of very real emotions (anxiety, frustration, perplexity, satisfaction, surprise) that feed the act of programming…
A number of classic dualities, essential to the way modernity organized the world, are put on hold or called into question here. It is difficult, for example, to draw a boundary between theory and practice, between the abstract and the concrete, or between science and art. The executable logic of the program brings together the immutable pureness of mathematics and the variability, unpredictability, and autonomy of living things. The programmer and the computer are creating together small simulated worlds, immaterial creatures made of fleeting flows of information.
_____________________________
This text was written at the request of Ricardo Vega M. for the magazine Visibles, arte y programación, soon to be published in Santiago de Chile.
Spanish version available here.
References:
[1] See Flusser, V. (1991). Gestures. Minnesota: University of Minnesota Press, 2014.
[2] On the relationship between users (or “functionaries”) and the programs of the devices they use, see Flusser, V. (2006). Towards a Philosophy of Photography. London: Reaktion Books, 2013.
[3] Bühler, K. (1934). Theory of Language: The Representational Function of Language. Philadelphia: John Benjamins Publishing Company, 1990.
[4] Jakobson expanded Bühler’s scheme by adding three new functions: metalinguistic, poetic or aesthetic, and phatic or relational. Jakobson, R (1960). Style in language. New York: M.I.T. See also https://en.wikipedia.org/wiki/Jakobson%27s_functions_of_language
[5] The so-called “graphic programming environments” represent this visually, replacing text for blocks (equivalent to functions) connected by lines (equivalent to variables). The resulting graphs brings to the surface the structure of the program, which makes them a valuable resource for teaching: they convey the particular way of thinking that is at stake in programming.