Why the stack is not always enough
The stack is a fine workspace, but it is a poor place to keep a value for a long time. If you need a total while you process many inputs, or a flag that several parts of the program consult, the value ends up buried under everything else, and every access means shuffling the stack. A variable gives the value a fixed home.
Befunge has no variable declarations, but its playfield is itself a store of numbers. Every cell holds a value, and two instructions let a program read and write any cell by its coordinates. Those are g (get) and p (put). A cell that no execution path ever visits is effectively a variable.
Argument order
Both instructions take coordinates from the stack, with x as the column and y as the row, counting from 0 at the top-left.
gpops y, then x, and pushes the value stored at (x, y).ppops y, then x, then a value, and stores that value at (x, y).
Since y is popped first, y must be on top. To store 5 at column 3, row 1, push the value, then x, then y, then use p. To read it back, push x and y and use g. A complete program:
531p31g.@
It pushes 5, 3 and 1, so the stack is 5 3 1 with 1 on top. The p pops y = 1, x = 3 and the value 5, and stores 5 at (3, 1). Then 3 and 1 are pushed again and g pops y = 1 and x = 3, pushing the stored 5. The . prints it. Row 1 is empty in this program, so nothing else uses that cell.
Getting the order backward is the most common mistake with these instructions. If the value ends up in the wrong cell, check which of x and y you pushed last.
A counter
The standard use is a counter that survives other stack activity. To add 1 to the variable at (3, 1):
31g1+31p
Read it left to right. 31g pushes the current value. 1+ adds one. 31p pushes the coordinates again, and p pops them together with the new value on the stack and stores it back. The stack is the same size at the end as at the start. Anything else on the stack stays below this sequence untouched, which is the point of the technique.
You can make this a routine, as described in the guide on grid subroutines, and call it from any place that needs to count.
What a cell actually holds
A cell holds an integer. When the program is loaded, each character is stored as its character code, so a cell you can see as v holds 118, and an empty cell holds 32, the code for a space. A p into an empty cell replaces the 32 with your value. When you read it with g, you get the number back.
This has two consequences. First, a stored number such as 5 is not a visible character on the grid. If you display the program later, the cell may appear blank or as a control character. Second, if your stored value happens to equal the code of an instruction and the pointer ever reaches that cell, it will run as that instruction. That is the connection to self-modifying code, and it is why variable cells need to be out of the way.
Choosing where variables live
A good variable cell is one the pointer will never execute and nothing else will overwrite. A few guidelines:
- Choose a dedicated region such as the bottom rows or the far right columns, and put all variables there.
- Keep the region away from the edges the pointer wraps through, so that a runaway path does not run over it.
- Remember the playfield in Befunge-93 is fixed in size, so coordinates must be within it. Some other dialects relax that limit, a difference described under Befunge-93 limits.
- Write a small table outside the program listing each name and its coordinates, since the grid itself has no names.
It helps to pick coordinates that are easy to push. Single digits can be pushed directly, so variables at coordinates 0 to 9 are convenient. Larger numbers need arithmetic such as 55+, which makes the code longer and harder to read.
Using variables for arrays
Because coordinates are just numbers, a row of cells can serve as an array. Compute the x coordinate, keep y fixed, and use g and p with the computed index. This is how programs hold more data than would be comfortable on the stack, as when sorting numbers in a small list. Check bounds yourself, since the instructions do not prevent you from writing into program code.
Combined with loops
A variable pairs well with a loop. Instead of keeping the loop counter on the stack, the program can store it in a cell, leaving the stack free for the loop’s actual work. The cost is a few extra instructions per access. It is usually worth it when the loop body does a lot with the stack, and not worth it for a tiny loop.
Debugging
When a value seems wrong, print the cell with a short g and . sequence at a few points to see where it changes. If the number is correct but the program behaves strangely, check whether the cell is also on an execution path. Tracing by hand with a column for each variable next to the stack makes mistakes much easier to see.