http://www.perlmonks.org?node_id=999655

squimby has asked for the wisdom of the Perl Monks concerning the following question:

So, I'm an utter noob learning Perl for work--and hopefully once I'm decent, to actually do things as well. Nonetheless, I'm trying to do an exercise in the O'Reilly camel book, but I can't get this subroutine working correctly:
sub total{ my $sum = shift(@_); foreach (@_){ $sum += @_; }
Any help? It always adds up to 17 when I include it in a script which throws in any number of arguments. Also: I'm trying to be more 'Perl Zen' but my code above looks like it'd be best friends with the cold and rigid likes of C++ or Java. Any tips for 'Perl'ifying this?

Replies are listed 'Best First'.
Re: Rook question
by NetWallah (Canon) on Oct 18, 2012 at 02:46 UTC
    Try this:
    sub total{ my $sum = shift(@_); foreach (@_){ $sum += $_; } return $sum; }
    • add $_, not @_
    • return $sum
    • Add trailing } to match braces

                 "By three methods we may learn wisdom: First, by reflection, which is noblest; Second, by imitation, which is easiest; and third by experience, which is the bitterest."           -Confucius

      Awesome! Fixed the problem--thanks much! I didn't know if Perl associated the default $_ while moving through the indices of @_.

        The mechanism of action is the foreach loop. It's just as happy aliasing $_ to elements of @this, @that, and @the_other as well. In this regard, @_ isn't special; foreach is.

        perlsyn


        Dave

Re: Rookie question
by Athanasius (Archbishop) on Oct 18, 2012 at 02:57 UTC
Re: Rook question
by sundialsvc4 (Abbot) on Oct 18, 2012 at 13:21 UTC

    One of the trickiest notions in Perl is the issue of contexts.   When you wrote $sum += @_, you used an @array value in a $scalar context.   That changes what it does.

    For debugging such things, I would insert a statement within the loop that prints useful information to the STDERR file, e.g.:
      print STDERR "sum is $sum\n";.

    All interactive programs have two output streams, STDOUT and STDERR, the latter intended for error or diagnostic outputs.

    Also, get used to now putting these two statements at the start of every program:
      use strict;
      use warnings;

Re: Rook question
by blue_cowdawg (Monsignor) on Oct 18, 2012 at 13:35 UTC

    another solution:

    sub total { my $sum =0; map { $sum += $_ } @_; return $sum; }
    Couldn't resist... :-)


    Peter L. Berghold -- Unix Professional
    Peter -at- Berghold -dot- Net; AOL IM redcowdawg Yahoo IM: blue_cowdawg

      Let's fold a list.

      use List::Util 'reduce'; sub total { return reduce { $a + $b } 0, @_; }
        The above code hardly even resembles Perl as I know it. Got a lot to learn... I've heard at work they use 'map' regularly (I wouldn't say 'frequently'--something about it not processing efficiently with mysql in some contexts). I'll need to read up on that.