Tape and Stack Languages

Tape and Stack Based Esoteric Languages

A comparison of esoteric languages that use a tape, a stack or a few counters as their only memory, and what each choice makes easy or awkward.

On this page
  1. One data structure, nothing else
  2. The tape model
  3. The stack model
  4. Counters, queues and other cousins
  5. What each model makes easy
  6. Why these languages are small but not weak
  7. Where the grid fits in
  8. Picking a starting point

One data structure, nothing else

Most everyday languages give you named variables, arrays, objects and a heap. A large family of esoteric languages throws nearly all of that away and keeps exactly one place to store data. The program remembers things on a tape, or on a stack, or in a few counters, and that is all. Working in these languages is a cheap way to see how little a programming model actually needs, and how much the choice of storage shapes the way you think.

The three most common choices are the tape, the stack and the counter. Each one has a famous language attached, and each has a theoretical cousin in the study of computation.

The tape model

A tape is a row of cells with a pointer that sits on one of them. The program can move the pointer left or right and change the value under it. Brainfuck is the best-known example. Its eight Brainfuck commands move the pointer, add or subtract one, read or write a byte, and open or close a loop that repeats while the current cell is not zero.

A tiny example shows the feel of it:

+++[>++<-]

The first part sets the first cell to 3. The loop then runs three times; on each pass it moves right, adds 2 to the second cell, moves back, and subtracts 1 from the first. When the first cell reaches zero the loop ends, and the second cell holds 6. Multiplication is built out of repeated addition because there is nothing else to build it from.

The tape model is a direct descendant of the Turing machine, which also reads and writes symbols on a tape. The difference is that a Brainfuck program is a separate fixed text and its tape holds only data. Practical interpreters typically use a finite tape, often tens of thousands of cells, whereas the theoretical model assumes unbounded memory.

The stack model

A stack is a pile where you can only touch the top. You push a value, pop a value, and operate on whatever sits at the top. Languages built on it usually read like a calculator with no brackets: 3 4 + pushes 3, pushes 4, then replaces both with 7.

Stack languages split into a few styles. Some, like Underload, are tiny and treat pieces of code as strings that can be stored, joined and run. Others follow the concatenative style, where a program is a sequence of operations applied one after another to the same stack. A third group borrows a stack for data but puts the code somewhere else, as the Befunge language does: its instructions live on a grid, while numbers live on the program stack.

Stacks make nested expressions and temporary values pleasant. They make it awkward to reach a value buried several items deep, so programs often spend a lot of effort shuffling items into position.

Counters, queues and other cousins

At the far minimal end sit counter machines. Instead of a tape or a stack, there are only a few registers that hold non-negative integers, with instructions to add one, subtract one and test for zero. They are very restrictive, yet a small number of counters can in principle be enough for universal computation, at the cost of enormous slowdowns.

Queues are another option: add to the back, remove from the front. Some well-known tiny models of computation work this way, and tag systems are a good example of how little a queue-style rewrite process needs.

What each model makes easy

Model Easy Awkward
Tape Walking through neighboring cells, keeping several named slots by position Copying values, since moving a value usually destroys the original
Stack Evaluating nested expressions, temporary values, recursion-like structure Reaching deep items, keeping many long-lived variables
Counters Proving things about computation Almost any practical task

The right-hand column explains why programmers who learn these languages develop habits quickly. On a tape you learn to reserve scratch cells. On a stack you learn to plan the order in which values are pushed so that they arrive where you need them.

Why these languages are small but not weak

Strangely, a language with one data structure and a handful of commands can still be Turing complete, meaning that in principle it can compute anything a conventional language can, given enough memory. The idea behind Turing completeness is that you only need conditional repetition and unbounded storage; everything else can be encoded. That is why the best minimalist languages are often interesting: they show where the real boundary of expressive power lies.

Real machines, of course, never have infinite memory. A finite tape or a stack with a depth limit turns the language into something weaker in theory, though programs written for such interpreters rarely notice the difference.

Where the grid fits in

The Funge family changes the question. Instead of asking where data lives, it asks where code lives, and answers that the program itself occupies a two-dimensional space that the instruction pointer travels across. Data still sits on a stack, which makes Befunge a hybrid. Comparing it with a pure tape language is a useful way to see which ideas are about memory and which are about control flow.

Picking a starting point

If you want to learn how loops and pointer movement work with the least machinery, begin with a tape language. If you are interested in expression evaluation and code as data, try a stack language. If your interest is theory, counter machines are the cleanest model to reason about. In practice many people start with Brainfuck because its rules fit on a postcard, then branch out once the tape idea feels natural.

Keep exploring

Guides from other topics

All topics →