Regan Heath:
FWIW I disagree. I think it's immediately and intuitively
obvious what 'i' should be when you're foreaching over X items
taken from another range, even if you do not know take returns
another range. Compare it to calling a function on a range and
foreaching on the result, you would intuitively and immediately
expect 'i' to relate to the result, not the input.
Using enumerate has several advantages. It gives a bit longer
code, but it keeps as much complexity as possible out of the
language. So the language gets simpler to implement and its
compiler is smaller and simpler to debug.
Also, using enumerate is more explicit, if you have an
associative array you can iterate it in many ways:
foreach (v; AA) {}
foreach (k, v; AA) {}
foreach (k; AA.byKeys) {}
foreach (i, k; AA.byKeys.enumerate) {}
foreach (i, v; AA.byValues.enumerate) {}
foreach (k, v; AA.byPairs) {}
foreach (i, k, v; AA.byPairs.enumerate) {}
If you want all those schemes built in a language (and to use
them without adding .enumerate) you risk making a mess. In this
case "explicit is better than implicit".
Python does the same with its enumerate function and keeps the
for loop simple:
for k in my_dict: pass
for i, v in enumerate(my_dict.itervalues()): pass
etc.
In D we have a mess because tuples are not built-in. Instead of
having a built-in functionality similar to what enumerate does,
it's WAY better to have built-in tuples. Finding what's important
and what is not important to have as built-ins in a language is
an essential and subtle design problem.
Bye,
bearophile