views:

225

answers:

4

Lately, I've decided to start using Perl::Critic more often on my code. After programming in Perl for close to 7 years now, I've been settled in with most of the Perl best practices for a long while, but I know that there is always room for improvement. One thing that has been bugging me though is the fact that Perl::Critic doesn't like the way I unpack @_ for subroutines. As an example:

sub my_way_to_unpack {
    my $variable1 = shift @_;
    my $variable2 = shift @_;

    my $result = $variable1 + $variable2;
    return $result;
}

This is how I've always done it, and, as its been discussed on both PerlMonks and Stack Overflow, its not necessarily evil either.

Changing the code snippet above to...

sub perl_critics_way_to_unpack {
    my ($variable1, $variable2) = @_;

    my $result = $variable1 + $variable2;
    return $result;
}

...works too, but I find it harder to read. I've also read Damian Conway's book Perl Best Practices and I don't really understand how my preferred approach to unpacking falls under his suggestion to avoid using @_ directly, as Perl::Critic implies. I've always been under the impression that Conway was talking about nastiness such as:

sub not_unpacking {
    my $result = $_[0] + $_[1];
    return $result;
}

The above example is bad and hard to read, and I would never ever consider writing that in a piece of production code.

So in short, why does Perl::Critic consider my preferred way bad? Am I really committing a heinous crime unpacking by using shift?

Would this be something that people other than myself think should be brought up with the Perl::Critic maintainers?

+5  A: 

It's important to remember that a lot of the stuff in Perl Best Practices is just one guy's opinion on what looks the best or is the easiest to work with, and it doesn't matter if you do it another way. Damian says as much in the introductory text to the book. That's not to say it's all like that -- there are many things in there that are absolutely essential: using strict, for instance.

So as you write your code, you need to decide for yourself what your own best practices will be, and using PBP is as good a starting point as any. Then stay consistent with your own standards.

I try to follow most of the stuff in PBP, but Damian can have my subroutine-argument shifts and my unlesses when he pries them from my cold, dead fingertips.

As for Critic, you can choose which policies you want to enforce, and even create your own if they don't exist yet.

friedo
That's an excellent point and I agree with it, but my concern is whether or not Perl::Critic in its default state is correct in saying that using subroutine-argument shift's are bad.
Weegee
+5  A: 

Running perlcritic with --verbose 11 explains the policies. It doesn't look like either of these explanations applies to you, though.

Always unpack @_ first at line 1, near 
'sub xxx{ my $aaa= shift; my ($bbb,$ccc) = @_;}'.
  Subroutines::RequireArgUnpacking (Severity: 4)
    Subroutines that use `@_' directly instead of unpacking the arguments to
    local variables first have two major problems. First, they are very hard
    to read. If you're going to refer to your variables by number instead of
    by name, you may as well be writing assembler code! Second, `@_'
    contains aliases to the original variables! If you modify the contents
    of a `@_' entry, then you are modifying the variable outside of your
    subroutine. For example:

       sub print_local_var_plus_one {
           my ($var) = @_;
           print ++$var;
       }
       sub print_var_plus_one {
           print ++$_[0];
       }

       my $x = 2;
       print_local_var_plus_one($x); # prints "3", $x is still 2
       print_var_plus_one($x);       # prints "3", $x is now 3 !
       print $x;                     # prints "3"

    This is spooky action-at-a-distance and is very hard to debug if it's
    not intentional and well-documented (like `chop' or `chomp').

    An exception is made for the usual delegation idiom
    `$object->SUPER::something( @_ )'. Only `SUPER::' and `NEXT::' are
    recognized (though this is configurable) and the argument list for the
    delegate must consist only of `( @_ )'.
mobrule
Neither do, which is why I'm concerned about whether or not Perl::Critic is checking the "Always unpack @_" case validly...
Weegee
+1 for '--verbose 11'
sebthebert
+6  A: 

The simple answer is that Perl::Critic is not following PBP here. The book explicitly states that the shift idiom is not only acceptable, but is actually preferred in some cases.

PBP reader
When I get home tonight I'm going to have to open the book up and read the section again, its been a while, but I think you might be right.
Weegee
Yep, I can confirm that now.
Weegee
+2  A: 

In some cases Perl::Critic cannot enforce PBP guidelines precisely, so it may enforce an approximation that attempts to match the spirit of Conway's guidelines. And it is entirely possible that we have misinterpreted or misapplied PBP. If you find something that doesn't smell right, please mail a bug report to [email protected] and we'll look into it right away.

Thanks,

-Jeff

Jeffrey Thalhammer
Thanks for posting here Jeff. I'm going to send an email tomorrow to the [email protected] email account about my concerns. I went back and re-read Section 9.3 in Conway's book and he even states, "Alternatively, you can use a series of separate shift calls as the subroutine's first 'paragraph'".
Weegee