Why a program would ask
A program written for one interpreter may run on another with a different cell size, a different number of dimensions or different support for files. Rather than guess, Funge-98 includes an instruction for asking. The instruction is written y, and it pushes a collection of facts onto the stack. The program can then choose a path based on the answers.
The answers describe three things: the interpreter itself, the state of the running program, and the surrounding environment. The exact list is defined in the language specification, and the numbering below follows the commonly documented order. Verify it against your interpreter before relying on a specific position.
How the instruction behaves
The instruction pops one value from the stack. What happens next depends on that value:
- If it is zero or negative, the instruction pushes the entire report, which is a long run of values.
- If it is a positive number, the instruction picks that numbered item from the report and pushes only that one.
Asking for a single item is nearly always more convenient. The full report is long, and its length varies with the number of dimensions, stacks and strings, so finding one value by hand is awkward. A program that wants one fact should push the item number and run the instruction.
A tiny example in a two-dimensional interpreter:
7y.@
Here the digit 7 asks for the item that describes the number of dimensions, the . prints the number, and @ ends the program. In a two-dimensional interpreter this is expected to print 2. Because the numbering is a convention to confirm, a test like this is a good first experiment in any new interpreter.
The sort of facts it reports
The report groups together several kinds of information. In rough order it typically includes:
- A flags value whose bits say which optional abilities exist, such as concurrency, file input, file output, command execution and whether input is buffered.
- The size of a cell in bytes. A commonly seen value is 4, though this varies.
- A handprint, an identifier that names the interpreter implementation, and a version number.
- An operating-paradigm value describing how the host treats the command-execution instruction, and the character used to separate directory names in paths.
- The number of dimensions.
- Per-pointer facts: an identifier for the current pointer, a team number, its current position, its current movement vector, and its storage offset.
- The least and greatest occupied points in the space, which describe the bounding box of the program.
- The current date and time, encoded as numbers.
- The sizes of the stacks in the stack of stacks, and how many stacks there are.
- The command-line arguments and the environment variables, given as strings.
Some items are numbers, some are vectors with one component per dimension, and some are sequences of text. Text items are stored with a zero at the end, and groups of strings are closed with an extra zero, so reading them back means popping until you see the terminators.
A practical use: checking before you rely
The flags item is a good example of defensive programming. If your program needs to write a file, it can check the relevant flag and print a message instead of hitting the unpredictable results of an unsupported instruction. Similarly, a program that stores large numbers can check the cell size. A cell that only holds a small range would break an algorithm that assumes bigger values.
This ties in with what happens when an instruction is unsupported. The instruction usually reflects the pointer, which can look like a silent bug. Asking first turns a mysterious failure into a clear decision.
Pitfalls to watch for
- Size of the full report. When you request the whole report, you often need to pop and discard many cells to reach the one you want. Prefer requesting a single item.
- Different dimensions, different vector lengths. A position or movement vector has one component per dimension, so the number of stack cells it takes depends on the interpreter. Check the dimensions item before reading vectors in portable code.
- Time-dependent values. Date and time change from run to run, so a program that prints them cannot be tested with fixed expected output. Treat them as inputs, not constants.
- Environment contents. Command-line arguments and environment variables differ between machines and sometimes contain private information. Do not print or write them out carelessly.
- Not every interpreter is complete. Some implementations fill unsupported items with dummy values. A returned value is not proof that the underlying ability works.
Why implementers care
For anyone building interpreters, this instruction is a good checklist. Supporting it forces you to decide, and document, your cell size, your handprint and your flags. It also gives test authors a cheap way to detect which features exist. If you are comparing interpreter behavior, a short program that prints a few of these items is a quick diagnostic, and it makes interpreter testing less guesswork.
A habit worth building
When you start using an unfamiliar interpreter, run a small program that prints the dimension count, the cell size and the flags. Keep the output as a record of what that environment supports. If a later program misbehaves, you can compare against those numbers before suspecting your own logic. The facts are small, but they remove a lot of guessing from the way a grid program adapts to the machine it lands on. The same query is also handy during grid debugging, since the current position and movement vector are right there in the report.