Tape and Stack Languages

Tape Versus Grid as a Memory Model

Contrast one-dimensional tape execution in Brainfuck with an instruction pointer moving over a plane in Befunge, and see where code and data live in each.

On this page
  1. Two pointers, two different jobs
  2. Where the code lives
  3. Where the data lives
  4. A same-task comparison
  5. Edges and boundaries
  6. Dimensions as a dial
  7. Consequences for programmers
  8. What the comparison shows

Two pointers, two different jobs

Brainfuck and Befunge both have a pointer that moves, and that similarity hides a deep difference. The two languages move different things for different reasons.

In Brainfuck, the program text is a fixed string that is read from start to end, with jumps backward and forward at brackets. A separate tape holds the data, and a data pointer moves along it. So there are two pointers, one for code and one for data, and they live in different places.

In Befunge, the program is laid out on a two-dimensional grid, and the instruction pointer moves across it, one cell at a time, in a direction that the program itself can change. Data mostly sits on a stack, and the grid can also hold data through get and put instructions. There is one pointer moving through code, and the data pointer does not exist.

Where the code lives

On a tape-style language, code is a line. Execution goes forward. A loop is a pair of brackets, and the only way to go back is to hit the closing bracket and jump to the match. The position in the program is a single number.

On a grid, code is a surface. Execution continues in the current direction until something turns it. Position is a pair of coordinates (or more, in higher-dimensional Funge), plus a direction. Loops arise from the geometry itself: a path that leads back to where it started is a loop, which is the idea behind geometric loops. The way grid-based flow works covers this in detail.

Where the data lives

On the tape, data is the tape. It is a row of cells, usually all the same type, with the pointer deciding which one is current. Getting to another cell means walking the pointer there. Data layout is the programmer’s job: where to keep the counter, where the scratch cells go.

In Befunge, numbers are mostly kept on the stack, and so the question of layout disappears for simple tasks. When the stack is not enough, programs store values in unused cells of the grid. The code and data then share a space, which is why dead code regions are sometimes reused for storage, and why a program can in principle rewrite itself.

A same-task comparison

Let us count down from 3, printing each value, using a hypothetical simple version of each language.

In a tape language, you put 3 in a cell, then loop: print the cell, subtract 1, repeat while nonzero. The loop is a bracket pair around the body, and the counter lives on the tape.

In Befunge, the counter lives on the stack. The program pushes 3, prints and decrements it, and the pointer reaches an instruction that sends it back left if the value is nonzero. The loop is a path on the page, not a pair of symbols. A countdown program is a good first example for seeing how that works.

The two programs compute the same thing, yet their shapes are opposite: one is a line with nested structure, the other is a picture with a route.

Edges and boundaries

A tape has ends, or it extends indefinitely in one direction. Moving off the left end is typically an error or a wrap, depending on the implementation. A grid has edges in every direction. Befunge’s grid wraps around, so a pointer leaving the right side reappears on the left, which makes the playfield behave like a surface with no boundary. This toroidal playfield is a design decision, not an accident; it ensures the pointer never falls off.

Dimensions as a dial

The distinction is not strictly two-versus-one. The Funge family treats dimensionality as a parameter. Unefunge puts the program on a line, which comes close to a tape-like layout, though the pointer can still reverse direction. Trefunge dimensions add a third axis. Seen this way, a tape is the one-dimensional end of a series, and a grid is the next step.

The difference between them is not simply one more axis but a change in role. In a Brainfuck-style design, the dimension belongs to the memory. In a Funge-style design, the dimension belongs to the program text. Direction and turning become a major part of the language, with pointer direction and delta vectors replacing the notion of a simple forward step.

Consequences for programmers

  • Readability: Tape code is linear and easy to scan, though dense. Grid code can be laid out so that its structure is visible, but it can also hide a path that is hard to follow. A trace on paper, as with tracing by hand, is the usual tool.
  • Debugging: On a tape, you inspect cells. On a grid, you follow the path of the pointer.
  • Writing: On a tape, you plan memory layout. On a grid, you plan geography, and you may need to route around or past other code.
  • Implementation: A tape interpreter needs an array. A grid interpreter needs a way to store a possibly sparse plane, as discussed in the playfield data structure topic.

What the comparison shows

Both models can express any computation in principle. The difference is in what the programmer has to think about. A tape asks you to manage where things are stored; a grid asks you to manage where the flow of control goes. Many people find that learning one makes the other clearer, because you see more precisely which idea belongs to the memory and which to the control flow. For the broader family of related languages, the two-dimensional languages group is the next place to look.

The complete guide to tape and stack languages

Tape and Stack Based Esoteric Languages
Read the guide

Keep exploring

Guides from other topics

All topics →

What Is Funge-98?

Funge-98 generalizes Befunge into a larger, better-defined family of grid languages. Learn its goals, its main differences from Befunge-93, and why it matters.

Funge-98 5 min read