http://qs321.pair.com?node_id=723849


in reply to Re^2: C-style for loop
in thread C-style for loop

Yes, one can use $_ instead of $i, but I talked about the loop specified by OP. And if in theory we can't say what type of a loop is better but in specific case we can.

Unfortunately OP gave not equivalent loops. The first one modifies original array and the second one creates new array with modified data. I rewrite in perl-style the first loop.

Replies are listed 'Best First'.
Re^4: C-style for loop
by GrandFather (Saint) on Nov 15, 2008 at 21:26 UTC

    I gave you a reason for preferring the Perl style for loop in general - fewer parts to go wrong. Eliminating a variable is not generally the important difference between two different for loop usages. Indeed:

    for my $index (0 .. $#array) { ... }

    Is generally a much better solution than:

    for (my $index = 0; $index < $#array; ++$index) { ... }

    because the range of the Perl loop is much easier to see and harder to get wrong.

    In general we can say what sort of for loop is better - Perl for loops. '"C-style" is bad because of useless $i variable' is not the reason however.


    Perl reduces RSI - it saves typing
      #!/usr/bin/perl -- use strict; use warnings; use Benchmark qw(cmpthese); my $BIG = 100_000; cmpthese(1000, { 'C-style' => \&c, 'P-style' => \&p}); sub c { for (my $i = $BIG; $i > 0; $i--) { 1; } } sub p { for my $i ( reverse 1..$BIG ) { 1; } } __END__ Rate P-style C-style P-style 26.7/s -- -44% C-style 48.0/s 80% --

      Is Perl-style still better?

        Absolutely if the point you are trying to make is that there is a tiny execution penalty in this rather artificial case for using the Perl style for loop. An interesting test is to change the loops from reverse to forwards and see where the differences lie. For the C style for loop you need to change every part of the loop header in a major way and you have to think a while to ensure the range is what you want:

        for (my $i = $BIG; $i > 0; $i--) { becomes for (my $i = 0; $i <= $BIG; $i++) {

        For the Perl loop just deleting the reverse does the trick and the range is still completely clear. Oh, and now the Perl loop overhead is less than the C loop overhead:

        #!/usr/bin/perl -- use strict; use warnings; use Benchmark qw(cmpthese); my $BIG = 100_000; print "c: ", c (),"\n"; print "p: ", p (),"\n"; print "cF: ", cF (),"\n"; print "pF: ", pF (),"\n"; cmpthese(-1, { 'C-style' => \&c, 'P-style' => \&p, 'C-styleF' => \&cF, 'P-styleF' => \&pF, }); sub c { my $sum = 1; for (my $i = $BIG; $i > 0; $i--) { $sum += $i; } return $sum; } sub p { my $sum = 1; for my $i ( reverse 1..$BIG ) { $sum += $i; } return $sum; } sub cF { my $sum = 1; for (my $i = 1; $i <= $BIG; $i++) { $sum += $i; } return $sum; } sub pF { my $sum = 1; for my $i ( 1..$BIG ) { $sum += $i; } return $sum; } __END__ c: 5000050001 p: 5000050001 cF: 5000050001 pF: 5000050001 Rate P-style C-style C-styleF P-styleF P-style 49.9/s -- -23% -33% -42% C-style 65.0/s 30% -- -13% -25% C-styleF 74.7/s 50% 15% -- -13% P-styleF 86.2/s 73% 33% 15% --

        Considering how small the overhead of using reverse is and how much more maintainable the Perl loop is you have done an admirable job of demonstrating why in the general case the Perl for loop is much better than the C style for loop.


        Perl reduces RSI - it saves typing
        • For for (X..Y), Perl uses a counting loop.
        • For for (reverse constX..constY), Perl builds a flattened list at compile-time and iterates over it in reverse.
        • For for (reverse X..Y), Perl builds a flattened list at run-time and iterates over it in reverse.

        So far, I've found 6 different kinds of for loops in Perl. You can find them in an earlier node.

        #!/usr/bin/perl -- use strict; use warnings; use Benchmark qw(cmpthese); my $BIG = 100_000; cmpthese(-3, { c_f => \&c_f, c_r => \&c_r, p_fv => \&p_fc, p_fc => \&p_fv, p_rc => \&p_rc, p_rv => \&p_rv, }); sub c_f { for (my $i = 0; $i < $BIG; $i++ ) { 1 } } sub c_r { for (my $i = $BIG; $i-- > 0; ) { 1 } } sub p_fc { for my $i ( 0..100_000-1 ) { 1 } } sub p_fv { for my $i ( 0..$BIG-1 ) { 1 } } sub p_rc { for my $i ( reverse 0..100_000-1 ) { 1 } } sub p_rv { for my $i ( reverse 0..$BIG-1 ) { 1 } } __END__ Rate p_rv c_r c_f p_rc p_fv p_fc p_rv 28.5/s -- -37% -44% -59% -64% -65% Builds list and loops. c_r 45.0/s 58% -- -11% -35% -44% -44% c_f 50.7/s 78% 13% -- -27% -37% -37% p_rc 69.7/s 144% 55% 37% -- -13% -14% Loops over pre-built array. p_fv 80.0/s 180% 78% 58% 15% -- -1% Counting loop p_fc 80.7/s 183% 79% 59% 16% 1% -- Counting loop

        If you add "()," to the front of any of the lists, you'll notice that p_* will become as slow as p_rv.

        It depends
        #!/usr/bin/perl -- use strict; use warnings; use Benchmark qw(cmpthese); my $BIG = 100_000; cmpthese( 1000, { 'C-style' => \&c, 'P-style' => \&p } ); sub c { for ( my $i = 1 ; $i <= $BIG ; $i++ ) { 1; } } sub p { for ( 1 .. $BIG ) { 1; } } __END__ Rate C-style P-style C-style 141/s -- -29% P-style 200/s 42% --
Re^4: C-style for loop
by blazar (Canon) on Nov 18, 2008 at 14:28 UTC
    Unfortunately OP gave not equivalent loops. The first one modifies original array and the second one creates new array with modified data. I rewrite in perl-style the first loop.

    I personally believe, ccn, that I can understand your point. More precisely, you also dropped a /msg to me, which I'm reproducing hereafter - I hope it's not a problem:

    Re Re^2: C-style for loop OMG! Please look at OP question. He asks about specific "this" loop, not general. I answered about that loop, not general! May be I said not what I actually mean. Not $i but *index* is useless there, coz we can iterate without it

    But then please let me get straight and direct and stress what quite about everyone is trying to say here:

    • first of all, the OP's post is ambiguous at best, with "this" being something that can mean quite about everything both general or very specific: I know he gives an actual example, but it may well be an actual example of what (s)he thinks to be a generic case;
    • the two loops even do different things, as you point out yourself in the first place!

    In view of all this, you did not "rewrite in perl-style the first loop:" but as a statement modifier, which is something still slightly different, albeit certainly more Perl-stylish than the C-style form of C<for> loop.

    --
    If you can't understand the incipit, then please check the IPB Campaign.