To bake a Hello World Souffle requires exactly 114 g sugar, 111 ml beaten eggs, 54 ml double cream, and 32 g cocoa powder. Most recipes measure by the number of eggs, rather than their volume in milliliters, and do not opt for a level of specificity appropriate more for a chemistry lab than a kitchen. However, this recipe is not only for cooking, but also serves as a computer program in the Chef language.
Chef is one of the best-known esolangs to embrace multicoding: where content has different meanings when considered in different contexts. The term (as "multiple coding") was coined by Michael Mateas and Nick Montfort in their "A Box, Darkly" (2005), the paper that first introduced many academics to esoteric and obfuscated coding practices. It uses the example of "Jean put dire comment on tap," a phrase that holds very different meanings in French and English. Programs can be multicoded on a few different levels. Malicious programs are sometimes written with a gap between its reading by a human and its actual execution by the machine. In our previous post, we looked at the case of Primify, which multicodes numbers and images. Programs known as polyglots have a single text that holds multiple meanings even to the machine itself, functioning differently when interpreted in more than one programming language.
When Chef appeared in 2003, it joined a slowly growing list of esolangs that are explicitly multicoding, although this term was not one used by their creators (they are usually simply described as "designed to make programs appear to be something else"). Its author, David Morgan-Mar (interviewed here), created the cult esolang Piet the previous year. Where Chef's programs multicode as cooking recipes, programs in Piet (pronounced "Pete") are images, with commands defined by the change in hue or lightness between adjacent pixelly blobs of color, called codels. Shakespeare (created 2001) has as its programs, long, rambling stage scripts. Whitespace (2003) uses only tab, space, and return. In Whitespace, commands are multicoded as what is normally read as their absence. These characters are treated interchangeably by C and C-derived languages, meaning Whitespace programs can be embedded between words in these programs, creating polyglot programs that function in both languages.
There were few precursors for these languages in the early '00s. Previous esolangs like brainfuck and Malbolge had unusual lexicons, but emphasized their puzzle-like logic. Multicoding languages don't generally have unusual logical systems, most are straightforward, procedural languages behind their odd vocabularies. More recent multicoding languages, like AshPaper and bodyfuck, have benefited from these forerunners, learning the lessons of how Shakespeare commands are constructed as dialogue. But at the time Shakespeare was written, it was intended primarily as both joke and provocation. Its creators likely had little expectation that esoprogrammers would continue to work with these languages and learn from them decades later. Otherwise, there would be alternatives to Shakespeare's repetitive "SPEAK YOUR MIND!" command. So it might seem unfair to overly critique their design decisions, but considering Chef's design more deeply can give us insight into how multicoding schemes function and help consider possibilities in multicoding strategies for future works.
Chef's Central Metaphor
Chef differs from Whitespace and Piet in the confluence of its central metaphor. While a cooking recipe might sound as arbitrary as the systems other esolangs use, it differs in that recipes already are algorithms. A recipe is a plan, worked out step by step: well-ordered, repeatable, and, given the expected input and faithful execution, produces the expected output. In fact, recipes have long held as an example of algorithmic thinking for non-programmers (see, for instance, the entry for Algorithm in the Simple English Wikipedia, which strives for simple explanations). Recipes, like other algorithms, break up continuous processes into discreet steps that can be carried out in an orderly way. In her Contingent Computation, M. Beatrice Fazi describes this systematizing of process as a "discretization of reality":
The digital is a technique of information processing that represents and manages data in the form of digits, such as, for instance, the zeros and ones of digital binary systems. In the computational, discreteness is similarly expressed via quantifying means, such as models, procedures, representations, symbols, numbers, measures, and formulizations. When we compute—digitally or not—we arrange reality into sets of abstracted relations between these quantifiable entities.
From p. 48, with the emphasis mine
In this way, cooking recipes are computational to begin with. A continuous process is made into bounded steps akin to lines of code in a procedural program: individual steps of an algorithm, explicitly spelled out. Where Piet uses a digital lexicon—a series of pixels—Chef uses a computational one.
Chef is not just a theoretical system that equates cooking and coding. Specific choices were made in mapping the two systems together, and the aesthetic of a multicoding language is defined by that mapping and the constraints it creates for its programs. Before considering how this works in Chef, we might look at how dual meanings are handled in Piet. Piet has a palette of twenty different colors. It has the black, white, red, yellow, blue used in the (later, abstract geometric) Mondrian works—but also magenta, green, and cyan, with three different shades of each. With a language named for Mondrian, we might ask why the palette wasn't restricted to the subtractive primaries. But Morgan-Mar didn't particularly want people to mimic Mondrian's style. If he did, he could have locked down the color choices and the layout of Piet geometries to lines and rectangles. In his interview with esoteric.codes, Morgan-Mar states that:
I think that Piet has proven itself a general enough medium now that programmers can achieve virtually any visual appearance they put their mind to. So I don’t like to think of it as constrained to any particular aesthetic—that would be limiting. I’d rather people tried to push the boundaries out and create something we haven’t seen yet.
Piet, while flexible enough to construct a range of different styles, encourages certain types of visual works. We can see it in the programs which don't attempt to contort into Mondrian-like imagery (or other specific styles), but instead are written in the simplest way, ending up often with dense configurations of codels from across Piet's spectrum, determined primarily by functionality, such as the two Prime Number Tests by Alexander Rodgers below (see more Piet programs here).
This tension between a multicoding esolang's constraints and its use as an all-purpose medium is at work in nearly all multicoding esolangs. All esolangs—multicoding or not—are open-ended works that are only fully explored by the esoprogrammers who discover the language's character by concretizing it in working programs. The tension in multicoding esolangs is between this open-endedness and the specificity of its rules. Programmers will stretch the language's design, making aesthetic discoveries that might surprise the esolang's creator. Where an individual program might have a specific aesthetic, it's what the great many programs written in the esolang have in common that describe the aesthetic of the language itself. This is reminiscent of the experimental writing movement Oulipo and other constraint systems that describe sets of rules but require many writers' experiments to discover what those rules allow for.
The Aesthetics of Chef
But what of the aesthetics of the Chef language? Does it allow a lot of freedom for its programmers, or do most Chef programs look (taste) the same? For insight on this, I reached out to Ian Bogost. Bogost, author of the excellent book Play Anything, which explores creativity within constraint-based systems, has taught Chef to creative coding students for 15 years. Teaching Chef for such as long time has made him responsible, by his account, for 99% of the world's Chef programs. He selected Chef to introduce code aesthetics for a few reasons:
I like Chef because it’s far more earnest. Nobody is going to perform an act of Shakespeare code; it’s mostly conceptual. But Chef is actually viable. I also like it because it multicodes in a gratifying and challenging way on multiple registers:
- The program runs and does something computationally interesting
- The code is legible and coherent as the text of a recipe
- The recipe is logically consistent and can be followed step by step in the kitchen as written
- When followed, the output of the recipe as recipe is gastronomically interesting and delicious
I always ask the students to try to write a Chef program that multicodes on all these registers. Some years, time willing, I invite students to bring in their cooked programs to share (and for a little extra credit).
This makes Bogost one of the very few who have tasted more than one completed Chef program. In Play Anything he includes a recipe written by a student that succeeds both algorithmically and gastronomically. He notes that "In Chef, the variables are 'ingredients'; the input is the 'refrigerator', the output and memory is a series of 'mixing bowls' and 'baking dishes', and the instructions are the steps of the recipe itself."
IRISH CREAM DESSERT SQUARES.
This recipe creates sapid dessert squares perfect for party, pleasure, and it also displays the square of any number.
1 package yellow cake mix
3 beaten eggs
12 tablespoons Irish Cream Liqueur
5 tablespoons oil
1 can of cream cheese vanilla frosting
61 white chocolate chips
Cooking time: 30 minutes.
Preheat oven to 180 degrees Celsius gas mark 4.
Take beaten eggs from refrigerator. Put beaten eggs into mixing bowl. Combine package of yellow cake mix into mixing bowl. Combine beaten eggs. Mix the mixing bowl well. Put oil into mixing bowl. Fold Irish Cream Liqueur into mixing bowl. Mix the mixing bowl well. Pour contents of mixing bowl into the baking dish. Put can of cream cheese vanilla frosting into 2nd mixing bowl. Combine white chocolate chips into 2nd mixing bowl. Liquefy contents of the 2nd mixing bowl. Pour contents of the 2nd mixing bowl into the baking dish.
Each Chef recipe begins with the list of ingredients; these are the program's variables. The 1 package yellow cake mix above introduces a variable called yellow cake mix, and sets its initial value to 1:
[initial value] [unit] [variable name].
The unit (here "package") has no meaning to the program, but is required for actually cooking.
Once we're past the ingredient lists, we get to Method. Some instructions translate in a somewhat intuitive way between cooking and program, but others surely put the esoteric in esoteric programming; an arcane list of cooking instructions and their translations provides the full list. One can see from this example is the centrality of the mixing bowls. The bowls are stacks where we can manipulate variables; multiplying by combining ingredients, or folding ingredients into the bowls, which actually means removing the variable from the stack that the bowl represents.
From the example above, here are a few of the steps in calculating the square of a number.
Take beaten eggs from refrigerator.
// This reads a numeric value from STDIN into the ingredient named, overwriting any previous value.
// get input from the prompt, assign to variable beaten eggs
Put beaten eggs into mixing bowl.
// This puts the ingredient into the nth mixing bowl.
Combine package of yellow cake mix into mixing bowl.
// This multiplies the value of ingredient by the value of the ingredient on top of the nth mixing bowl and stores the result in the nth mixing bowl
Fold Irish Cream Liqueur into mixing bowl.
// Remove the top element of the mixing bowl and put into variable Irish Cream Liqueur
Liquefy contents of the 2nd mixing bowl.
// Turns elements of mixing bowl 2 into Unicode values
Note the dual thinking necessary to understand some of the instructions. There are three eggs—or rather three eggs worth of beaten, eggy material throughout the making of the Irish Cream Dessert Squares. We never return a few to the fridge or add more. However, the "beaten eggs" variable never makes use of the value 3, it is wiped out as soon as we take the eggs out of the fridge, replaced with user input. Meanwhile, by folding the Irish Cream Liqueur into the mixing bowl—adding it to what is already in the bowl—we are actually performing the opposite action in code, removing the top element of the stack that bowl represents and storing it in the variable Irish Cream Liqueur.
So we can't easily visualize the algorithmic steps through the cooking steps; they are often contradictory. Keeping these conflicts in mind becomes a challenge to the programmer. Others are less so: putting a variable in a mixing bowl adds that variable to the stack, and mixing is randomizing.
The 61 white chocolate chips are required because the Unicode value of 61 is "=", which the program will write to the screen. If you are not writing any text, you end up with much more natural-seeming numbers, as in this other student example from Bogost's class:
BOSTON CREME PI.
For the chef who loves a good math pun. This recipe can make real-world Boston Creme Pie while also using pi (the glaze) to find the volume of a sphere (⁴⁄₃πr³). The radius is the value of the flour ingredient. The solution is at the top of the stack in the resulting bake dish. The pie is in the bake dish! Bon appetit!
2 cups cake flour
1 teaspoon baking powder
1 teaspoon salt
4 beaten eggs
2 cups sugar
2 cups whole milk
1 cup vegetable oil
1 teaspoons vanilla extract
3 cups glaze
Put cake flour into the mixing bowl. Add baking powder into the mixing bowl.
Add salt into the mixing bowl. Combine vanilla extract into the mixing bowl.
Put vegetable oil into the mixing bowl. Put whole milk into the mixing bowl.
Mix the mixing bowl well. Pour contents of the mixing bowl into the baking dish.
Serve with pudding.
Combine sugar into the mixing bowl.
Combine beaten eggs into the mixing bowl. Combine glaze into the mixing bowl.
Pour contents of the mixing bowl into the baking dish.
Text issues are singled out by Bogost in making Chef a challenge for the students:
In some ways, I wish Chef didn’t do text, because it invites a few major issues. The first is that a computer program that outputs a short string is just not that interesting. The second is that Unicode values require very high numeric data, which either results in insanely large quantities of ingredients or requires complex looping to multiply small values up. And the third is that text output requires liquid ingredients or “liquefying” a mixing bowl, which just produces a slurry that probably nobody wants to eat if prepared.
The looping Bogost refers to is the norm in many other esolangs. In brainfuck, we would never represent the number 61 the default way: with 61 + signs in a row. Instead, we would get to 61 by multiplying—which in brainfuck is actually adding repeatedly in a loop—to have fewer instructions. And if "=" is the first character in a string, we would manipulate that number, rather than starting again at zero, requiring another large constant. This can be done in Chef, which has commands to multiply (Combine *ingredient* [into [nth] mixing bowl]) as well as looping (by *verb*ing the ingredient). In this way, we don't need to introduce more numbers than a set of factors to multiply to create the capital H of Hello World. Once we get to H, we can add to that number to produce the numerical equivalent of e's, l's, etc., with loops like this:
Mash the potatoes. [begin loop]
Combine celery into first mixing bowl. [multiply celery by radishes]
Mash the potatoes until mashed [end loop]
Given 3 radishes already in the mixing bowl, and an ingredient list including 2 potatoes and 12 pieces of celery, we'd now have 72, the Unicode value for capital H. We can build a string (actually a baking tray), beginning with this number and then manipulate it in sequence to get to "Hello, World!".
So the unusual numbering, while a marker of a recipe probably being a Chef recipe, is not always necessary; like the Whitespace programs hidden in C source files, it's possible to write a recipe that is more discreet with its double-meaning. The mixing bowls, however, are more likely to mark a recipe as a Chef program. This aspect is one that Bogost found troublesome:
The mixing bowl/baking dish paradigm definitely impacts the viability of Chef recipes in a negative way. As a culinary counterpart to the stack data structure, it’s just not a great match for many types of recipes—that, plus the liquefaction problem—makes Chef mostly good for baked goods. So long as that constraint is acknowledged and respected up front, the results can be really interesting.
Bogost adds that translating an existing recipe and hoping to rework it in Chef is just not possible most of the time. This, however, is all part of the learning experience.
No matter what happens, and whether they love or hate the experience, the students never seem to forget Chef and their experience with it.