statements. In this case, the execution of the current instruction causes the program counter’s value to change, so that it points to some other location in memory. In either situation, the code that runs next is sitting somewhere in memory; it is directly fetched and run. In standard machine models, the instructions as laid out in memory are exactly the instructions the machine will execute.
Malbolge, in contrast, performs a complicated transformation on the instruction pointed at by the code pointer before executing it. As the manual states:
When the interpreter tries to execute a program, it first checks to see if the current instruction is a graphical ASCII character (33 through 126). If it is, it subtracts 33 from it, adds C [the code pointer] to it, mods it by 94, then uses the result as an index into the following table of 94 characters:
If the character indexed in the table is one of the seven characters corresponding to Malbolge operations, the operation is executed. Otherwise the machine does nothing, except to increment both the code pointer and the data pointer (the constant incrementing of the data pointer provides another annoyance for the programmer). Note that the transformation depends on where the instruction resides in memory because C (the code pointer) is added as part of this step; the same value would execute as two different instructions at two different locations in memory. A Malbolge programmer cannot lay out the instructions she wants executed, but must lay out instructions so that after they have been taken through this complicated transformation, the eventual result will be the instructions that were supposed to be executed in the first place. To make matters more difficult, Malbolge programs can only consist of the seven characters that correspond to operations; the programmer can’t simply write a program consisting of non-operation characters that will transform to operations.
Mandatory self-modifying code. In standard programming practice, code is treated as immutable. Though both code and data reside as patterns in memory, the block of memory patterns corresponding to code remains fixed, while the block of memory patterns corresponding to data is manipulated by the executing code. Self-modifying code treats its code block as mutable, literally changing its own operations as it runs. Self-modifying code is notoriously difficult to read and write; where the textual representation of the program is by necessity static, the structure of the process dynamically changes over time. In Malbolge, the programmer is forced to write self-modifying code, as code modification is built into the definition of code execution:
After the instruction is executed, 33 is subtracted from the instruction at C, and the result is used as an index in the table below. The new character is then placed at C, and then C is incremented.
So, in addition to the complexities added by the indirect instruction decoding, the instructions are constantly changed by an arbitrary transformation. It is therefore impossible to write code in Malboge that does the same thing twice in a row. These factors account for the two years that passed before the first Malbolge “hello, world” program appeared.
discovered a number of “weaknesses” that made it possible to
write arbitrary programs in Malbolge — proving, therefore, that is is capable of universal computation. The most notable weaknesses are as follows: The permutation table used to modify code exhibits short cycles — that is, if one chooses carefully, instructions can be selected that turn back into themselves before very long. Specifically, a permutation cycle is a sequence of code transformations that comes back to itself. For example, the p instruction (the crazy op), when located at memory location 20, will turn into the j instruction (to store a value in memory) the first time it is executed, then into a “no op” (do nothing) once the j instruction is executed, then into another no op when the no op is executed, and finally, after this no op is executed, back to the p instruction. Another forgiving aspect of Malboge is that the branch instruction, i, is not modified, nor is its target. Exploiting these regularities allowed Scheffer to develop general Malbolge code constructs that, for example, allow one to create a block of code that performs a given function every other time it is executed, one that safely does nothing the alternate times. These discoveries paved the way for the creation of a BrainFuck to Malbolge compiler.
11. TOWARD A BROADER CODE AESTEHTICS
Programs in weird languages generally have the property of being difficult to read. This suggests that weird languages may be “auto-obfuscating,” requiring obfuscation from programmers. But obfuscated code contests are not about merely producing code that is hard to read; they are about exploiting the syntax and semantics of the language to comment on the language itself. Weird languages emphasizing minimalism and puzzles are “merely” hard to read in the same way that assembly language is hard to read; they provide so little play that it is virtually impossible to double-code interestingly. Languages structuring play, in contrast, are hard to read because of the insistence of the enforced double-coding. The textual meaning of the program is inevitably not about the procedural meaning of the program, but about some unrelated domain. Of the weird languages described here, it may be only INTERCAL that is truly auto-obfuscating. Since INTERCAL parodies several languages, resulting in a language in which nothing can be expressed cleanly or elegantly, the difficulty of reading INTERCAL programs is a result of such programs being about the parody languages, and thus in some sense about INTERCAL itself.
By commenting on the nature of programming itself, weird languages point the way towards a refined understanding of the nature of everyday coding practice. In their parody aspect, weird languages comment on how different language constructions influence programming style, as well as on the history of programming language design. In their minimalist aspect, weird languages comment on the nature of computation and the vast variety of structures capable of universal computation. In their puzzle aspect, weird languages comment on the inherent cognitive difficulty of constructing effective programs. And in their structured play aspect, weird languages comment on the nature of double-coding, how it is the programs can simultaneously mean something for the machine and for human readers.
All of these aspects are seen in everyday programming practice. Programmers are extremely conscious of language style, of coding idioms that not only “get the job done”, but do it