Inspired by Sygmei's question, I'm interested in finding out what languages can "do this properly".

Your task is to write a "for loop" function / macro / instruction. The arguments should be:

  • an initializer
  • a test
  • an increment
  • a body

All of these are "pieces of code" and should be able to access variables in the context of the call. The body should be able to include multiple statements.

The aim is to have the fewest lexical tokens excluding comments, except that #define and friends (using a dumb preprocessor) are worth 50, and eval and friends (taking a string argument) are worth 100. Feel free to make your code readable with comments, whitespace and meaningful names.

You should include a "test harness" which is not counted towards length.

The C version definitely won't win:

// the do {...} while (0) idiom enables a code block to be a single C statement, so it can safely be followed by a semicolon
#define my_for(init, test, inc, body) do {  \
    init; \
    while (test) { \
        body; \
        inc; \
    } \
} while (0)

// test harness:
#include <stdio.h>

    int i, total;
    my_for((i=1, total=0), i<=3, ++i, {printf("%d\n", i); total=total+i;});
    printf("total: %d\n", total);

Edit to add: the meaning of "lexical token" depends on your language. Here's how the scoring breaks down for my C version:

//[...]: 0
#define: 1 occurrence, 50 points
my_for: 1
(: 3
init: 2
,: 3
test: 2
inc: 2
body: 2
): 3
do: 1
{: 2
\: 6
;: 3
while: 2
}: 2
0: 1


  • 3
    \$\begingroup\$ Unclear to me: scoring. For example how would your c reference be scored? \$\endgroup\$ – Digital Trauma Jan 27 '17 at 4:42
  • \$\begingroup\$ I was actually going to do this challenge, but I ran into a fair number of difficulties in laying it out. I hope someone posts a well explained version; preferably normal code golf. \$\endgroup\$ – Carcigenicate Jan 27 '17 at 16:18
  • \$\begingroup\$ @DigitalTrauma does my edit clarify it sufficiently? If so how can I get the question re-opened? I can't tag all the on-hold-voters in this comment \$\endgroup\$ – Hugh Allen Jan 28 '17 at 2:40
  • \$\begingroup\$ The C scoring only makes it clear for C programs. It's very hard to define "tokens" for a wide range of languages. You either have to give up on the idea, or only allow a narrow range of languages (which is a whole different can of worms). \$\endgroup\$ – Mego Jan 28 '17 at 4:29
  • \$\begingroup\$ 1) Can it be a lambda (anonymous function), or does it have to be a named function? 2) Is it okay to use the language's built-in for loop syntax in the implementation? \$\endgroup\$ – smls Jan 28 '17 at 22:28

Python, 11 26 tokens:

def f(n, t, i, l):
    while t():

This is my first time doing , so forgive me if I got the token counting wrong.

EDIT: Hugh Allen informed me that I got the token counting wrong.

  • \$\begingroup\$ The thing is, atomic-code-golf doesn't actually exist. \$\endgroup\$ – feersum Jan 27 '17 at 6:17
  • 5
    \$\begingroup\$ @feersum It has 44 questions. How does it not exist? \$\endgroup\$ – Post Rock Garf Hunter Jan 27 '17 at 19:36
  • \$\begingroup\$ That's a nice answer, but it's more than 11 tokens! See my edit for clarification (I hope) \$\endgroup\$ – Hugh Allen Jan 28 '17 at 2:41
  • \$\begingroup\$ I can't see your edit. Could you explain to me why it's more than 11 tokens? \$\endgroup\$ – Esolanging Fruit Jan 28 '17 at 6:05
  • 1
    \$\begingroup\$ @HughAllen So 26 tokens? \$\endgroup\$ – Esolanging Fruit Jan 28 '17 at 19:27

Perl 6, 24 tokens

sub my-for (&init, &test, &inc, &body) {
    while (test) { body; inc }


while   1   keyword
sub     1   keyword
my-for  1   function name (declaration)
&init   1   function parameter (declaration)
&test   1   function parameter (declaration)
&inc    1   function parameter (declaration)
&body   1   function parameter (declaration)
init    1   function name (implicit call)
test    1   function name (implicit call)
inc     1   function name (implicit call)
body    1   function name (implicit call)
,       3   parameter list separator
;       2   statement separator
{       2   block opener
}       2   block closer
(       2   parameter list opener
)       2   parameter list closer


my ($i, $total);
my-for {$i=1; $total=0}, {$i <= 3}, {++$i}, {
    say $i;
    $total = $total + $i;
say "total: $total";

tcl, could I say 0 due to point 1.?

If the question was "how many ways your language allow you to do it", tcl would certainly score a good amount.

  1. for

The language's normal for works this way; it should me noted that tcl has no keywords, so for works exactly like a function (side note: its behaviour can even be redefined!). Then, there is no need to implement it:

for {set i 0;set total 1} {$i<=3} {incr i} {puts $i; incr total $i}
puts total:\ $total
  1. proc

Implement a function, strictly according to the question.

2.1. uplevel

The uplevel 1 will execute its contents 1 level up in the call stack, to allow there the access to the variables of the for input; otherwise we could not access $total, because it would be not defined.

proc F {s t i b} {uplevel 1 [list for $s $t $i $b]}
F {set i 0;set total 1} {$i<=3} {incr i} {puts $i; incr total $i}
puts total:\ $total

2.2. tailcall

From tailcall documentation: "The tailcall command replaces the currently executing procedure, lambda application, or method with another command."

proc P args {tailcall for {*}$args}
P {set i 0;set total 1} {$i<=3} {incr i} {puts $i; incr total $i}
puts total:\ $total
  1. interp alias

You can say to one of the interpreters currently existing on interpreters tree that a command has an alias. I didn't create any interpreter, so I am interested on the tree's root interpreter, which path is an empty string, represented by {}. The following line means: "Create the alias R on the root interpreter, which will re-route calls to it to for on the root interpreter.

interp alias {} R {} for
R {set i 0;set total 1} {$i<=3} {incr i} {puts $i; incr total $i}
puts total:\ $total
  1. set

You can define a var that will have the same value has for command:

set S for
$S {set i 0;set total 1} {$i<=3} {incr i} {puts $i; incr total $i}
puts total:\ $total
  1. rename

You can change the name of the function. Note: From now on, you can not call for directly again! Now you must always call f, until you rename it back!

rename for f
f {set i 0;set total 1} {$i<=3} {incr i} {puts $i; incr total $i}
puts total:\ $total


  • \$\begingroup\$ 1. Almost every language has a "for" loop; giving the builtin one is definitely cheating. 2. uplevel is like eval and is worth 100 points! \$\endgroup\$ – Hugh Allen Jan 29 '17 at 1:59

Not the answer you're looking for? Browse other questions tagged or ask your own question.