[% setvar title Implicit counter in for statements, possibly $#. %]

This file is part of the Perl 6 Archive

Note: these documents may be out of date. Do not use as reference!

To see what is currently happening visit http://www.perl6.org/


Implicit counter in for statements, possibly $#.


  Maintainer: John McNamara <jmcnamara@cpan.org>
  Date: 16 Aug 2000
  Last Modified: 27 Sep 2000
  Mailing List: perl6-language-flow@perl.org
  Number: 120
  Version: 5
  Status: Frozen
  Frozen since: v3


The syntax of the Perl style for statement could be augmented by the introduction of an implicit counter variable. The deprecated variable $# could be used for this purpose due to its mnemonic association with $#array.

Other alternatives are also proposed: an explicit counter returned by a function; an explicit counter defined after foreach; an explicit counter defined by a scoping statement.


The use of for and foreach statements in conjunction with the range operator, .., are generally seen as good idiomatic Perl:

    @array = qw(sun moon stars rain);
    foreach $item (@array) {
        print $item, "\n";

as opposed to the "endearing attachment to C" style:

    for ($i = 0; $i <= $#array; $i++) {
        print $array[$i], "\n";

In particular, the foreach statement provides a useful level of abstraction when iterating over an array of objects:

    foreach $object (@array) {

However, the abstraction breaks down as soon as there is a need to access the index as well as the variable:

    for ($i = 0; $i <= $#array; $i++) { # Note
        $array[$i]->index = $i;
    # Note - same applies to: foreach $i (0..$#array)

Here we are dealing with array variables and indexes instead of objects.

The addition of an implicit counter variable in for statements would lead to a more elegant syntax. It is proposed the deprecated variable $# should be used for this purpose due to its mnemonic association with $#array. For example:

    foreach $item (@array) {
        print $item, " is at index ", $#, "\n";


Following discussion of this proposal on perl6-language-flow the following suggestions were made:

Alternative 1 : Explicit counter returned by a function

This was proposed by Mike Pastore who suggested reusing pos() and by Hildo Biersma who suggested using position():

    foreach $item (@array) {
        print $item, " is at index ", pos(@array), "\n";
    # or:
    foreach $item (@array) {
        $index = some_counter_function();   
        print $item, " is at index ", $index, "\n";

Alternative 2 : Explicit counter defined after foreach

This was proposed by Chris Madsen and Tim Jenness, Jonathan Scott Duff made a similar pythonesque suggestion:

    foreach $item, $index (@array) {
        print $item, " is at index ", $index, "\n";

Glenn Linderman added this could also be used for hashes:

    foreach $item $key ( %hash ) {
        print "$item is indexed by $key\n";

Ariel Scolnicov suggested a variation on this through an extension of the each():

    while (($item, $index) = each(@array)) {
        print $item, " is at index ", $index, "\n";

With this in mind Johan Vromans suggested the use of keys() and values() on arrays.

A variation on this is an explicit counter after @array. This was alluded to by Jonathan Scott Duff:

    foreach $item (@array) $index {
        print $item, " is at index ", $index, "\n";

Alternative 3 : Explicit counter defined by a scoping statement

This was proposed by Nathan Torkington. This behaves somewhat similarly to Tie::Counter.

    foreach $item (@array) {
        my $index : static = 0; # initialized each time foreach loop starts
        print "$item is at index $index\n";
    # or: 

    foreach $item (@array) {
        my $index : counter = 0; # initialized to 0 first time
                                 # incremented by 1 subsequently
        print "$item is at index $index\n";


There was no discussion about how this might be implemented. It was pointed out by more than one person it would inevitably incur an overhead.



Alex Rhomberg proposed an implicit counter variable on clpm: x53.deja.com&fmt=text and x52.deja.com&fmt=text

Craig Berry suggested $#: x52.deja.com&fmt=text