[ Flip Home
| Language Description
| Programs
| Mail
authors
]
The Flip Language
Contents
The architecture of Flip is a two-dimensional grid of squares, in each
of which can be placed an object. The source code of a program is
simply a map of this space.
The program execution is performed in Flip by one or more balls,
which move around
and interact with the objects (Flip is a little like a game of
billard. If you play Programmers' Billard). Each ball contains a
numerical value1.
When a Flip program is executed, there is just one ball - of
numerical value 0 - which is placed in the upper left corner of the program
(the beginning of the source code) and moving to the right. This ball is
called the initial ball.
You will here learn the operating principles of Flip; the
different objects in Flip are introduced step-by-step,
along with a series of sample programs demonstrating the behaviour of
these objects.
The objects with which the balls interact are represented in the
source code as characters.
Some ASCII characters (called meaningful characters) correspond to
object kinds; others (meaningless characters) don't.
Flip programs may contain meaningless characters as well as meaningful ones;
this is not regarded as an error.
This enables you to write comments in your programs - you only need to
make sure that the balls do not accidently hit meaningless characters
(if this happens, the program will terminate with an error message).
An overview of the object kinds can be found after the tutorial.
Walls
Balls simply bounce off walls, as you would expect.
There are four kinds of wall:
| Wall |
| - | horizontal wall |
| | | vertical wall |
| / | diagonal wall |
| \ |
Diagonal walls make the ball go in a new direction, perpendicular to
the old one; horizontal and vertical walls make a ball turn around.
Horizontal and vertical walls are also called mirrors, and
diagonal walls are also called flippers (especially if they're
modified - we'll get to that).
In this program, the ball moves right until it hits the upper diagonal
wall, then down to lower diagonal wall, then left again. Then it hits
the vertical wall, and retraces its path back to where it started. It
continues left and out of the program.
Simple and intuitive, so far.
Diagonal walls - flippers - can be modified to alter their behaviour, but more about that later.
Sluices
Another important flow-directing object type is the sluice.
It is a device which allows motion in one direction, but not in the other.
There are four kinds of sluice:
| Sluice |
| > | 'right' sluice |
| < | 'left' sluice |
| ^ | 'up' sluice |
| v | 'down' sluice |
A sluice works like this:
If a ball hits a sluice moving in the direction in the sluice (eg.,
hits a ^ sluice moving upwards), it just
continues.
If it hits it in the opposite direction, it is reflected 180°.
And finally, if it hits the sluice from one of the sides, it is
deflected 90° such that it continues in the direction of the sluice.
In this program, the ball passes through the first sluice, hits the
sluice labeled '2', is deflected down, hits '3', is deflected left,
hits '4', is deflected up, and hits the sluice labeled '5'.
This sluice it hits against its direction, so it is reflected
downwards, where it hits '4', is again reflected, and so on.
If the '5' sluice was removed, the ball would move in a square going
between the other four sluices.
Sluices can be modified to alter their behaviour, but more about
that later.
Number Generators
Number Generators generate numbers.
That is, they generate new balls with specified numbers as their values.
A such new ball is generated when a ball hits the number generator;
the new ball will be moving in the direction of the hitting ball, and
the hitting ball will be reflected 180°.
Number generators exist to create a ball with any one-digit number (in
decimal).
| Number Generator |
0 1 2 3 4 5 6 7 8 9 |
number generator |
Sample program 3:
Number Generators
When the initial ball hits the '2', it is reflected and leaves the
program to the left. A new 2-ball is created at the impact, moving
right. When it hits the '4', a 4-ball is created - it leaves the
program shortly after, to the right. The 2-ball bounces back and hits
the '2', creating a 2-ball which leaves to the left. The first 2-ball
will keep bouncing back and forth between the two numbers, generating
2's and 4's which escape from the program, forever.
With number generators come, of course, the opportunity (although in
Flip it is close to a necessity) of creating multi-threaded programs.
Binary Arithmetics
Now, there isn't really a reason for having different numbers, if you
can't do calculations on them, is there?
There are two types of objects, which can do binary arithmetics -
these are for soon obvious reasons also known as tarpits:
| Tarpit |
| + | additive tarpit |
| * | multiplicative tarpit |
A tarpit works like this:
If a ball hits an empty tarpit, it gets stuck and stays in the tarpit.
When another ball then hits the tarpit, the sum or product - as the
case may be - of the balls' numbers are formed, and a single ball with
this value continues in the same direction as the second original
ball. The two original balls do not exist anymore.
Sample program 4:
Arithmetics
The initial balls passes through the sluice, and then keep bouncing
between the '2' and the sluice, generating series of 2-balls.
The first 2-ball gets stuck on the '+'-tarpit, where it waits for the
second 2-ball. From the two, a 4-ball is formed, which then gets stuck
on the '*'-tarpit, waiting for the next 4-ball (which is generated
from the third and fourth 2-ball). A 16-ball is formed from the two
4-balls and leaves the program to the right. All in all, the effect
of the program is to create a series of such 16-balls.
Notice that the 16-ball is represented as '6' on the screen;
balls are always just represented by their last decimal digit.
Unary Arithmetics
They unary operations are:
| Unary Arithmetics |
| ~ | invert sign (negate) |
| ' | increment |
| , | decrement |
| . | reset |
These object alter the value of the balls which hit them (the balls
continues through them). The reset operator resets a ball's value to zero.
Sample program 5:
Unary operators
After going through the operators, the ball has the value -2.
Output
It would be nice, now we can do arithmetics, to be able to print out
balls' values - at least it enables us to verify that the 16-balls
generated by Sample Program 4 are indeed 16-balls and not 6-balls.
There are two kinds of output objects:
| Output |
| p | print out values in decimal |
| P | print out as ASCII character |
Balls disappear when they hit an output object, after being printed
out.
A ball hitting an ASCII output object will result in the ASCII
character corresponding to the ball's value being printed.
Sample program 6:
Arithmetics with Output
This program is an extension of Program 4, and repeatedly prints '16'.
Note: When printing out decimal values, a space character is
automatically printed after each value for convenience.
Sample program 7:
ASCII Output
This program demonstrates ASCII output; a series of 64-balls are
generated and printed out ASCII-wise (as the '@' character).
Input
In Flip it is also possible to read input.
Input works similar to output:
| Input |
| r | read values in decimal |
| R | read ASCII characters |
If an input object is hit by a ball and some input is ready then the
value of the ball is set to the input value.
If no input is ready then the behaviour depends of the value of the
ball:
| Input-ball |
| zero | The ball is erased. |
| positive | The ball is trapped, waiting for
input. |
| negative | The program is suspended until input
is ready. |
If multiple balls are trapped waiting for input then one of them is released
as soon as more input is ready - the others keep on waiting. It is
unspecified which of the balls is selected.
Sample program 8:
Input
> 0 r ' p
==========================
This program inputs a series of numbers, increases them by one, and
prints them out again.
Sample program 9:
Program suspending Input
> 1~ r ' p
==========================
This program is almost identical to the previous one.
The difference is that because the numbers are read by a negative
number then the program is frozen whenever no input is ready. - The
balls travelling tovards the p are halted as soon as no input is
ready. This
means that the first number isn't printed until 8 numbers have been
read.
Program Termination
As one of our goals with Flip is for it to be
Turing-complete, it would be nice if Flip-programs could
terminate. Here is the appropriate object:
| Program Control |
| Q | terminate program |
The program terminates, when a ball hits the terminator. The program's
exit value is that of the ball.
The Grille
The grille lets balls with positive values pass, but eats balls with
zero or negative values (they are simply too small).
Sample program 10:
The Grille
In this program, a 2-ball is created and sent over a grille - it
passes.
Try removing the '2' - you can then see that the initial 0-ball won't
pass, but is eaten.
The Processor
The processor is so named, because it is able to perform many
different functions, depending on how it is modified.
In its basic form, however, it'll only do one thing, namely clone a
ball.
When an unmodified processor is hit by a ball, it is made into two
identical clones, leaving the processor in opposite directions at
90° to the direction of the original ball.
Sample program 11:
The Processor
3 \ p
/ X +
\ X
Q /
=============
A 3-ball is generated and sent into a processor for cloning.
One copy hits a '+'-tarpit. The other is cloned again; one copy hits
the waiting ball in the '+'-tarpit a little later, causing '6' to be
printed; the last clone makes the program terminate shortly after.
As mentioned, processors can be modified to alter their behaviour,
but more about that later.
Those were the basic, real objects; now we get to the interesting topic of
modifiers. These are markers that tell flippers, sluices and
processors to act differently - and when to do so.
Until now, we can hardly just output the sum of two different numbers
(and do so once) - with modifiers, things are a little more flexible.
| Modifiers |
| Name | Meaning |
|---|
| @ | always | always true |
| + | positive | value > 0 |
| - | negative | value < 0 |
| 0 | zero | value = 0 |
| ~ | odd | value is odd |
| % | random | random truth value |
(yes, some of these characters are also used for normal objects).
If there is more than one random-modifier around the object, they'll all
respond with the same truth value.
Modifiers are placed in the four squares one step diagonally from an
object. Which modifiers are placed where does matter.
There is a seventh modifier, namely false. And actually, all
modifiable objects always have four modifiers - but as default, these
are all false unless another is specified.
Modifiers are mostly grouped together. The value of the group's
response on a ball is then the exclusive or of the responses of
the modifiers in the group. In this way, it is possible to make many
useful, and some useless, combinations.
Modified Flipper
A diagonal wall can be modified to flip - that is, change its
orientation at impact. The flipping is decided by the modifier group
containing the modifiers in the corners in the wall's current
direction (that is, the upper left and lower right modifier for a
\, and the upper right and lower left modifier for a
/).
Sample program 12:
Modified Flippers
\ \ \ \
@ @ @
2 3 4
p + + / Q
=================
In this program, the inital ball is deflected downwards by the first
flipper, while at the same time flipping it. The deflected ball
generates a 2-ball and
returns to the flipper, which deflects it to the right. In the same
way, the initial ball generates a 3-ball and 4-ball.
The 2-ball and 3-ball get stuck on the '+'-tarpits; the 4-ball
triggers the additions 4+3=7 and 7+2=9. The resulting 9-ball is then
output, and right after that, the 0-ball makes the program terminate.
Thus, the effect of this program is to add 2, 3, 4 and print the result.
Modified Sluice
Remember that a sluice will reflect a ball hitting it in the opposite
direction of the sluice? That behaviour can be altered with modifiers
into deflecting the ball to the left or to the right instead.
The direction of the deflection is determined by the modifier groups
containing the modifiers at either side - left or right, as seen by
the ball - by the following rule:
If the truth values given by the modifiers are equal, the ball is
relected.
Otherwise, the ball is deflected in the direction whose modifier group
returned true.
Sample program 13:
Modified Sluices
> 5 \ p
@ ~ @
> <1
~
> 4 / \
@
\ Q
=============
In this program, the initial ball passes through the first sluice,
generates a 5-ball, and on its way back, it is deflect downwards by
the modified sluice. Likewise, it generates a 4-ball.
The 4-ball and 5-ball are both sent to the sluiced marked with a '1';
here, the 5-ball is deflected downwards and sent out of the progam,
because the'down' modifier group has condition 'odd'.
The 4-ball, however, does not fulfill the condition 'odd', but it
fulfills the upward condition, which is 'odd XOR true' - that is,
'even'.
Thus, '4' is printed, and the inital ball make the program terminate.
Modified Processor
The processor can clone, sort or remove balls, depending on its
modifiers.
When hit by a ball, a processor can send out a copy of the ball in
each of the two directions perpendicular to where it was hit from - or
it can chose not to send out a copy. As the default, it does send one.
You can suppress the copies by telling the processor to do so, with
modifiers. The relevant modifier groups are the ones which contain
modifiers in directions adjacent to the output direction in question.
For example, let's say a processor is hit by a ball from the
left. Normally, it would send out copies of that ball upwards and
downwards (instead of the original ball).
If we now want to send out a ball upwards only if the original ball
was positive, we modify the processor by placing appropriate modifiers
on its up-left and up-right neighbour squares - in this case, either a
('zero' + 'negative') modifier combination or a ('positive' + 'always')
modifier combination will do.
Likewise, which balls are output downwards can be selected by placing
modifiers on the down-left and down-right neighbour squares.
Sample program 14:
Modified Processor
(or the Odd/Even Sorter)
> \ p / \
' ~ @
\ X X
~\ > /
=======|=====|==========
In the left part of this program, a ball cycles around. For each
cycle, a clone is passed on to the middle part, and the ball's
value is incremented by 1.
In the middle part, the balls are sorted. The processor sends the odd
balls upwards (it stops the ('odd' XOR 'all'), that is, the even
balls) for printing, and the even balls are sent downward (odd balls
are prevented).
Just for the fun of it, the even balls are sent to the right part of
the program: An infinite storage loop for the balls. (you could also
place a '+' tarpit somewhere in the loop, in which case the even
numbers will all be added...)
There is no reason the 'upward'- and 'downward'-conditions should be
opposite, as they are in this sample program - you might as well choose
to let the odd balls go up, while 50% of the balls are randomly chosen
to go downwards. Processors are flexible.
This is a new feature in version 2.0
Because the values contained in the balls cannot be arbitrarily
large - for practical reasons, there is a fixed limit - the language
as described so far is not Turing complete, i.e. it is not possible to
write all the programs which can be written in most other programming
languages.
The levels aspect of Flip changes this. It is relatively
simple: Instead of just the two dimensions we've seen so far, in Flip
you actually have three.
The space is divided into mostly independent levels (or
layers), each containing a copy of the 2D source program.
This means that all levels look alike, in that the same objects are
present on all levels, in the same places. But there can be certain
differences:
- Flippers can have different orientation on different levels - that
is, they are flipped individually.
- Tarpits trap different balls on different levels: A tarpit can be
empty on one level, have trapped a ball with one value on another
level and a ball with another value on a third level.
There are an (in theory, at least) infinite number of layers,
arranged as floors in an infinitely high tower. Thus, there is one layer
for each of the natural numbers and zero. Level zero is the
lowest level (the ground floor; there is no basement). This is where
the inital ball starts.
These are the object kinds dealing with levels:
| Levels |
| Z | go up one level |
| N | go down one level |
The behaviour of 'Z' is simple: Every ball passing through it is
raised one level. Similarily, every ball passing through an 'N' is
lowered one level. There is one small twist, though: Balls on
level zero cannot be lowered, and they are therefore reflected by 'N'.
This makes is possible to test whether a ball is on level zero.
Sample program 15:
Levels
> 2 4 \
#@
\ Z +
\
==============
This program is an extension of program 3. As in the original, a
stream of 4-balls is generated to the right and a stream of
2-balls to the left. Each stream is directed towards the '+' tarpit,
but because the 2-balls are first elevated one level, the two streams
actually pass through different tarpits.
When the program is run, can be seen that although a 4-ball
seemingly arrives on the tarpit at a time when a 2-ball is trapped
there, no addition takes place - the 4-ball is trapped too. This
demonstrates that the two balls are indeed on different levels.
The effect of the program is thus to produce a series of 8-balls
(made from 4-balls) and a series of 4-balls (made from 2-balls).
Sample program 16:
Going up and down
> 0 > \
@ / ' \
\ Z \ > N /
1 @
p
===|=======|====
In this program, both 'N' and 'Z' are demonstrated.
The program is divided into three parts. The left part consists of a
simple generator of 0-balls.
In the middle part, the orientation of the flipper labeled '1' is tested.
If it is in its original position ('\'), the ball is sent to the
right part of the program, and at the same time, the flipper is
flipped. Otherwise, the ball is raised one level and the flipper on
that level is tested, and so on.
The effect is that the first ball is passed on to the right on level zero,
the next ball on level 1, the third on level 2, etc.
In the right part of the program, the ball is sent through an 'N'.
If it is on level zero, then it is reflected by the 'N', deflected by
the sluice and its value is printed out.
Otherwise, the value of the ball is incremented by 1 and the ball sent
through the 'N' on the new (lower) level.
The effect on this part of the program is that each ball is sent to
level zero, and at the same time incremented by the number of its
original level.
All in all, this program prints "0 1 2 3 ...".
(The same effect could of course have been obtained much easier, but it is a
nice program anyhow.)
| Objects |
|---|
| Class | | Name |
|---|
| Wall |
- | horizontal wall |
|---|
| | | vertical wall |
| / | diagonal wall |
| \ |
| Sluice |
> | 'right' sluice |
|---|
| < | 'left' sluice |
| ^ | 'up' sluice |
| v | 'down' sluice |
| Number Generator |
0 |
number generator |
|---|
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
| Tarpit |
+ | additive tarpit |
|---|
| * | multiplicative tarpit |
| Unary Arihtmetics |
~ | invert sign (negate) |
|---|
| ' | increment |
| , | decrement |
| . | reset |
| Output |
p | print out values in decimal |
|---|
| P | print out as ASCII character |
| Input |
r | read values in decimal |
|---|
| R | read ASCII characters |
| Levels |
Z | Up one level |
|---|
| N | Down one level |
| Program Control |
Q | terminate program |
|---|
| Grille |
# | grille |
|---|
| Processor |
X | processor |
|---|
| Modifiers |
| Name | Meaning |
|---|
| @ | always | always true |
| + | positive | value > 0 |
| - | negative | value < 0 |
| 0 | zero | value = 0 |
| ~ | odd | value is odd |
| % | random | random truth value |
1) The ball values are really 32-bit signed values -
overflow may occur.