Visual and 2D Languages

Fish and Other Mirror-Based Languages

How Fish (written ><>) steers its pointer with mirrors and arrows, how that compares with Befunge, and what the two approaches mean for reading and writing code.

On this page
  1. The family resemblance
  2. What a mirror does
  3. A small Fish example
  4. Comparing the approaches
  5. Other tools Fish adds
  6. Other languages with mirrors
  7. Which should a newcomer learn first?

The family resemblance

Fish, usually written as ><> and pronounced “fish”, is a language that Befunge programmers tend to find familiar. The program is a grid of characters. An instruction pointer starts at the top left and moves one cell at a time. Data lives on a stack, and when the pointer runs off one edge it reappears on the opposite side.

Where it differs is how you turn the pointer. Befunge’s main tool is the arrow: reach a > and you head right, reach a v and you head down. Fish keeps arrows, with the same characters, and adds mirrors, which reflect the pointer like a ray of light.

What a mirror does

A mirror is a cell that changes the pointer’s direction depending on which way it was already going. Fish uses the slash and backslash characters for diagonal mirrors, and a vertical bar and underscore for mirrors that reverse one axis. There is also a hash mark that reflects in every direction.

Take the forward slash. A pointer moving right hits it and turns up, and one moving down turns left. Think of the slash as a ray bouncing off a line drawn from lower left to upper right. The backslash is the same idea mirrored left to right. The pointer arriving from a different side gets a different result, which is the key difference from an arrow: an arrow turns you to its direction no matter how you arrive, while a mirror’s outcome depends on your approach.

A small Fish example

Here is a program that prints “Hi” and stops, using a turn in the middle:

>v
 >"iH"oo;

The pointer starts on the first cell, heading right. It passes to the v, which turns it down. On the second row it meets the > and heads right again. The quote switches on string mode, so i and H are pushed onto the stack. The next quote ends string mode. Each o pops a value and prints it as a character, giving H and then i. The semicolon ends the program.

The Befunge version of the same idea would use , for printing and @ for stopping, in the usual Hello World program for that language. The shape and the logic carry over almost unchanged, which is the main reason people switch between the two easily.

Comparing the approaches

Arrows and mirrors are two ways to draw a path, and each has trade-offs.

Arrows are explicit. Each one names its direction. When you read a Befunge grid you can see the destination from the cell alone, which makes tracing by hand straightforward.

Mirrors are context-dependent. You have to know the incoming direction to know the outgoing one. That makes a path more compact, since a single character can serve two routes. It can also make a program feel more like a puzzle in optics.

Mirrors allow neat layouts. Because a slash can bounce a pointer into a column and another bounce can send it back, diagonal-looking paths and tight zigzags are easy to draw. In arrow-based layouts you often need a turning arrow on every corner.

Arrows cost more characters. A path that bends many times needs an arrow for each bend. A mirror-based design may reach the same shape with the same number of cells, so neither is always shorter.

Other tools Fish adds

Fish is more than Befunge with different corners. A few differences are worth knowing, stated generally:

  • It has a conditional-skip instruction that jumps over the next cell depending on the value on top of the stack, rather than choosing between two directions. In use, it feels closer to the Befunge trampoline instruction plus a test than to Befunge’s two-way if.
  • It has a random direction instruction, much like the question mark in Befunge, which picks a direction at random. See random direction for the Befunge side of that.
  • It has commands to get and put values in the grid, so a Fish program can modify itself, just as a Befunge one can.
  • Its stack is not the only storage: it also offers a register for holding a value.
  • Programs may create more than one stack, as the stack stack in Funge-98 does, and move values between them.

These details vary a little between interpreters, so check the documentation of whichever one you use.

Other languages with mirrors

Fish is the best-known case, but the idea is not exclusive to it. Some languages that lay code on a hexagonal grid use mirror characters too, because mirrors are an economical way to turn a pointer when there are many directions. The article on programming on a hexagonal grid touches on this.

There are also puzzle games and visual simulations in which beams and mirrors are the whole game. They are not programming languages in the usual sense, but they exercise the same spatial reasoning.

Which should a newcomer learn first?

If you are new to grid languages, Befunge is probably the gentler start. The rules are small and arrows are easy to read. Once you can trace a program, Fish gives you a second system with the same skeleton, and the comparison deepens your understanding of both.

A useful exercise: take a small Befunge program that uses a few arrows and rewrite it in Fish, replacing some corners with mirrors. See whether the new version is easier or harder for you to read. People differ here. Some find the mirrors elegant, and others find the dependence on direction of arrival a burden. Either answer is fine.

The complete guide to visual and 2d languages

Visual and Two-Dimensional Programming 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