## DEV Community

Tomasz Wegrzanowski

Posted on • Updated on

# 100 Languages Speedrun: Episode 27: Whenever

Whenever is a little known esoteric language where the program is a todo list of items.

Any actionable item can be executed, in whichever order the program feels like.

Oh and there are no variable, no functions, and none of the usual stuff, so it will be fun!

### Hello, World!

Hello, World! is very easy - just one todo item to print "Hello, World!". As there's no other items on program's todo list, that's what's going to happen.

1 print("Hello, World!");

It does exactly what we'd expect:

\$ whenever hello.txt
Hello, World!

### Any Order

Let's

1 print("Cats");
2 print("Are Better Than");
3 print("Dogs");

There's 6 possible outputs, here's two of them:

\$ whenever anyorder.txt
Dogs
Are Better Than
Cats
\$ whenever anyorder.txt
Cats
Are Better Than
Dogs

### Loop

Here's a simple loop that prints 1 to 10, without variables.

1 2#9;
2 defer (1) print(11 - N(2));

What the hell is going on here?

• 2#9 means put todo task 2 on the list 9 more times.
• defer (1) means that the task 2 cannot be done if task 1 is still pending
• N(2) checks how many times task 2 is on todo list, including current one. The first time it's executed N(2) is 10.
• So 11 - N(2) starts as 11 - 10, that is 1
• next time line 2 is executed, N(2) is 9, so 11 - N(2), that is 2, is printed
• and so on until 11 - 1, that is 10, is printed, and there's nothing more to do

### Odd Even

Before we do the Fizz Buzz, let's try something simpler - Odd Even loop.

It's very easy to modify the original program to print "1 is odd", "3 is odd" and so on until some predefined value. We need to adjust the formula to be A - N(lineno) * 2 to step by 2, for some value of A (we could either calculate with math, or adjust until we find the right value).

It's just as easy to modify the original program to print "2 is even", "4 is even" and so on.

The only difficulty is to make the loops run in sync, and for that they should look at each other's counters in defer condition:

1 2#4,3#4;
2 defer (1 || N(2) < N(3)) print((11 - N(2) * 2) + " is odd");
3 defer (1 || N(2) == N(3)) print((12 - N(3) * 2) + " is even");

Which generates:

\$ whenever oddeven.txt
1 is odd
2 is even
3 is odd
4 is even
5 is odd
6 is even
7 is odd
8 is even
9 is odd
10 is even

### Fizz

To keep complexity low, let's do the Fizz - the FizzBuzz version with just the Fizz rule.

We could just do 3 interlocking loops. To keep things simple let's keep them at same number of iterations, so it prints numbers 1 to 18:

1 2#5,3#5,4#5;
2 defer (1 || N(2) < N(4)) print(19 - N(2) * 3);
3 defer (1 || N(3) == N(2)) print(20 - N(3) * 3);
4 defer (1 || N(4) == N(3)) print("Fizz");

Which outputs:

\$ whenever fizz.txt
1
2
Fizz
4
5
Fizz
7
8
Fizz
10
11
Fizz
13
14
Fizz
16
17
Fizz

We could do 15 of such loops for FizzBuzz, and add some +1s to condition to make it print unequal number of them, but how about we try something else?

### Emulating Variables

This code is much longer, but it might be a lot easier to understand:

1 2#-1,3#-1,4#-1,6#-1,7#-1;
2 2;
3 defer(1) print(N(2));
4 defer(1) print("Fizz");
5 defer(1 || 3 || 4) 2,3,6;
6 defer(1 || 3 || 4) 2,3,7;
7 defer(1 || 3 || 4) 2,4,5;

It produces infinite Fizz:

whenever fizz2.txt | head -n 20
1
2
Fizz
4
5
Fizz
7
8
Fizz
10
11
Fizz
13
14
Fizz
16
17
Fizz
19
20

There's much less magic here, and it's very systematic way to do programming:

• line 1 initializes all counters. They start as 1,2,3,4,5,6,7, but we only want to have 5 as todo list, so we remove everything else.
• to make sure initializer runs, everything except 1 and 2 has defer(1) condition.
• 2 2; is a todo list that just reschedules itself when executed, so we basically created a variable. As it does nothing there's no need to put defer(1) condition on it.
• Whenever doesn't allow mixing print statements and line statements, so todo items 3 and 4 do various kinds of printing. If any printing is todo, everything after that is deferred.
• and everything that follows is loop condition. 5 doing 2,3,6 is like N(2)+=1 (2), print(N(2)) (3), and goto 6 (6).

### FizzBuzz

So let's try to do FizzBuzz:

1 2#-1,3#-1,4#-1,5#-1,6#-1,8#-1,9#-1,10#-1,11#-1,12#-1,13#-1,14#-1,15#-1,16#-1,17#-1,18#-1,19#-1,20#-1,21#-1;
2 2;
3 defer(1 || N(2) > 100) print(N(2));
4 defer(1 || N(2) > 100) print("Fizz");
5 defer(1 || N(2) > 100) print("Buzz");
6 defer(1 || N(2) > 100) print("FizzBuzz");
7 defer(1 || 3 || 4 || 5 || 6 || N(2) > 100) 2,3,8;
8 defer(1 || 3 || 4 || 5 || 6 || N(2) > 100) 2,3,9;
9 defer(1 || 3 || 4 || 5 || 6 || N(2) > 100) 2,4,10;
10 defer(1 || 3 || 4 || 5 || 6 || N(2) > 100) 2,3,11;
11 defer(1 || 3 || 4 || 5 || 6 || N(2) > 100) 2,5,12;
12 defer(1 || 3 || 4 || 5 || 6 || N(2) > 100) 2,4,13;
13 defer(1 || 3 || 4 || 5 || 6 || N(2) > 100) 2,3,14;
14 defer(1 || 3 || 4 || 5 || 6 || N(2) > 100) 2,3,15;
15 defer(1 || 3 || 4 || 5 || 6 || N(2) > 100) 2,4,16;
16 defer(1 || 3 || 4 || 5 || 6 || N(2) > 100) 2,5,17;
17 defer(1 || 3 || 4 || 5 || 6 || N(2) > 100) 2,3,18;
18 defer(1 || 3 || 4 || 5 || 6 || N(2) > 100) 2,4,19;
19 defer(1 || 3 || 4 || 5 || 6 || N(2) > 100) 2,3,20;
20 defer(1 || 3 || 4 || 5 || 6 || N(2) > 100) 2,3,21;
21 defer(1 || 3 || 4 || 5 || 6 || N(2) > 100) 2,6,7;
22 defer(N(2) <= 100) 2#-N(2),3#-N(3),4#-N(4),5#-N(5),6#-N(6),7#-N(7),8#-N(8),9#-N(9),10#-N(10),11#-N(11),12#-N(12),13#-N(13),14#-N(14),15#-N(15),16#-N(16),17#-N(17),18#-N(18),19#-N(19),20#-N(20),21#-N(21);

It works perfectly:

\$ whenever fizzbuzz.txt
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
16
17
Fizz
19
Buzz
Fizz
22
23
Fizz
Buzz
26
Fizz
28
29
FizzBuzz
...

It's a lot longer than an usual FizzBuzz, but really not that much more complicated:

• initializer in 1 only leaves 7, 22, resets everything else
• 2 is the only variable
• 3 to 6 are various print statements
• printing does not progress if initializer is todo, or if N(2) > 100
• 7 to 21 are various loop parts - each increments the variable, schedules some printing and goes to next step of the loop
• printing does not progress if initializer is todo, or any printing is todo, or if N(2) > 100
• finally 22 is exit condition - if N(2) > 100 it's the only thing that can execute and it sets all other counts to 0.

### Another Fizz

Let's try a different approach, starting with just Fizz part again.

1 2#-1,3#-1,4#-1,5#-1,6#-1;
2 2;
3 3;
4 defer(1 || (N(5) + N(6)) != 1) 5#-N(5),6#-N(6);
5 defer(1 || N(3) == 0) print(N(2));
6 defer(1 || 3) print("Fizz");
7 defer(1 || 4) 2,3,-3#((N(3)/3)*3),4,5,6,7;

What's going on here?

• initializer in 1 only leaves 7, resets everything else
• 2 is variable N
• 3 is variable N % 3
• 4-6 are the print system. To issue print command all of them should be scheduled exactly once.
• 4 sees that one of the print commands finished (so only 1 is remaining), so it clears all of them.
• 5 and 6 are various print statements, depending on N(3), that is N % 3
• condition 3 is shortcut for N(3) != 0, documentation says !3 should work for the opposite condition, but isn't actually implemented
• If we could do print and change in the same statement, we could get away with just 6 defer(1 || 3) print("Fizz"),-5; and not need 4, but that's just part of Whenever design.
• 7 is our loop iteration
• 7 increments 2 (N)
• 7 increments 3, then it decrements it by ((N(3)/3)*3). That expression is 0 if N(3) is less than 3, then it becomes 3. So as a result N(3) loops 0, 1, 2, 0, 1, 2, etc.
• 7 schedules printing with 4, 5, 6 - print system will run either (5 then 4) or (6 then 4), depending on N(3)
• 7 schedules itself to run again, but it will wait for the print system.

### Another FizzBuzz

1 2#-1,3#-1,4#-1,5#-1,6#-1,7#-1,8#-1,9#-1;
2 2;
3 3;
4 4;
5 defer(1 || (N(6) + N(7) + N(8) + N(9)) != 3) 6#-N(6),7#-N(7),8#-N(8),9#-N(9);
6 defer(1 || N(3) == 0 || N(4) == 0) print(N(2));
7 defer(1 || 3 || N(4) == 0) print("Fizz");
8 defer(1 || N(3) == 0 || 4) print("Buzz");
9 defer(1 || 3 || 4) print("FizzBuzz");
10 defer(1 || 5 || N(2) >= 100) 2,3,-3#((N(3)/3)*3),4,-4#((N(4)/5)*5),5,6,7,8,9,10;
11 defer(1 || 5 || N(2) < 100) -2#N(2),-3#N(3),-4#N(4),-10#N(10);

It follows all patterns from the previous Fizz - with just extra variable for N%5 (4), a few more prints (5-9), loop exit condition (11), and extra check in main loop iteration for loop exit (10).

### Should you try Whenever?

I stumbled upon this language entirely by accident, I've never seen anything like it, and as far as I can tell it's virtually unknown even among esoteric language lovers.

The existing Java interpreter is a bit low quality:

• it doesn't compile on latest Java without some trivial tweaks (enum is now a keyword so quite search and replace)
• it doesn't have good debug output (what we want is state)
• it doesn't optimize away NOPs, so it can be extremely slow, trying to execute do-nothing code (variables like 2 2; or code with defer checks preventing it from running).
• it doesn't even fully follow its own spec, especially lacking ! operator

But language itself is just brilliant. I hope someone writes a better interpreter for it, with in-browser visualization. To be honest I like it so much I might even do it at some point.

I definitely recommend giving it a try.