What makes a cell unreachable
In an ordinary language, dead code is a statement that can never run, such as lines placed after an unconditional return. A grid program has the same idea, with a spatial twist. Because the pointer follows a route, only the cells along its possible routes can ever run. Any other cell is unreachable: the pointer does not step on it, so whatever character is there has no effect as an instruction.
The size of that unvisited area is often large. A grid is a rectangle, but the routes through it are thin lines. A short program drawn on a large playfield leaves most of the area blank, and even in a dense program there are often rows and corners that no path passes through.
Dead code versus empty space
It helps to separate three kinds of unvisited cells.
- Blank cells. Spaces that the pointer may pass over harmlessly. Passing through a blank cell is not the same as being unreachable; the pointer does visit it and does nothing.
- Leftover instructions. Characters that look like code but are never reached, perhaps because an edit changed the route. This is the true counterpart of dead code in other languages.
- Deliberate data. Characters placed in unreached cells on purpose, to be read as values rather than run as instructions.
The first is invisible, the second is a maintenance problem, and the third is a technique.
Using unreachable cells as data
Many grid languages let a program read the character in any cell of its own playfield. The reading instruction typically takes two coordinates from the stack and pushes the character code found at that position. That means any cell can be a value holder, whether or not the pointer ever walks on it. A cell the pointer never visits is a safe place to keep a value, because nothing will accidentally execute it.
Here is a small example in Befunge-style notation. Row zero is the program, and row one holds a single letter:
01g,@
A
The pointer starts at the top-left, moving right. 0 and 1 push those numbers, so the stack holds an x of 0 and a y of 1. The g instruction removes the y and then the x and pushes the character at that position, which is the A on the second row, so its code, 65, goes on the stack. The comma prints it as a character, and @ ends the program. The output is A. The second row is never visited by the pointer, yet it is part of the program because the first row looks it up.
This is the basic idea behind grid variables: the program uses spare regions of its own space as memory. It also explains how a table of constants, such as a lookup of letters or numbers, can be written directly into a corner of the playfield.
When “data” is read as code
The line between data and code is only about the route. If the pointer ever does arrive in a data cell, it runs whatever character is there. A letter that is harmless on its own might be an instruction in the language. This can cause a nasty class of bugs, so planners usually keep data well away from any path or put it where the pointer cannot reach, such as past a wall of redirecting arrows.
There is one exception worth knowing. In most Befunge-like languages, quote-based string mode makes the pointer walk across cells and push each character code instead of running it. The cells there are visited, but they are treated as data. So they are not unreachable in the strict sense, although they behave similarly to data storage.
Reachability is not always obvious
How do you know whether a cell is ever visited? For a small, straight program, you trace the route and see. In bigger programs, whether a cell is reachable can depend on input, on the stack, or on cells changed during the run. In general, answering “will this program ever reach this cell?” for any program is as hard as the halting problem, so it falls among the undecidable properties of grid programs, and no tool can answer it for every case. Practical tools make guesses, such as marking cells that no arrow or fall-through could reach. Still, they cannot replace reading and testing.
That uncertainty is one more reason for careful grid debugging. Marking visited cells while running a program on test inputs is a useful way to find cells that were never entered, though not a proof that they are unreachable for other inputs.
Self-modification changes the picture
If a program can write to its own cells, a cell that is dead at the start can become reachable later, and a live instruction can be replaced by a harmless one. A static look at the grid is then no longer enough. That is part of the cost of self-modifying code, which has its own article in this cluster.
Practical habits
- Put data in a clearly separate area, such as a dedicated row or corner, and keep paths away from it.
- Check that no arrow, wrap-around or branch can send the pointer into that area.
- Remove leftover instructions after editing, or the next reader will wonder whether they matter.
- Treat any change to a path as a reason to re-check which cells are reachable.
Used with care, unreachable cells are free storage that shows up in the picture. Used carelessly, they hold stale code that quietly misleads the person reading the program.