ok 1 - mca is mutating does not offend Perl::Critic ok 2 - choroba is NOT mutating offends Perl::Critic Expression form of "grep" at line 6, column 5. See page 169 of PBP. Expression form of "map" at line 6, column 20. See page 169 of PBP. ok 3 - tux is NOT mutating does not offend Perl::Critic ok 4 - eplam is mutating does not offend Perl::Critic Rate eplam choroba mca tux eplam 41701/s -- -2% -40% -54% choroba 42626/s 2% -- -39% -53% mca 69930/s 68% 64% -- -23% tux 91241/s 119% 114% 30% -- 1..4 #### use 5.14.2; #use warnings; no strict 'refs'; no warnings 'uninitialized'; use Perl::Critic; use Test::More; use Benchmark qw( cmpthese ); # Returns non-empty strings with leading and trailing spaces removed. my %tests = ( mca => <<'MCA', sub mca # McA { grep { $_ ne "" } map { s/^\s+//; s/\s+$//; $_ } @_; } MCA tux => <<'TUX', sub tux # Tux { map { defined $_ ? m/(\S(?:.*\S)?)/ : () } @_; } TUX choroba => <<'CHOROBA', sub choroba # choroba { grep !m/^$/ => map s/^\s+|\s+$//gr => @_ } CHOROBA eplam => <<'EPLAM', sub eplam # eyepopslikeamosquito { grep { !m/^\s*$/ && s/^\s*|\s*$//g } @_; } EPLAM ); my @orig = (" hello ", "\thello again\t", "", " ", undef, " \t", "jock", "\t abc", "def \t "); my @e = ("hello", "hello again", "jock", "abc", "def"); my @x; # Configure Perl::Critic as you will: my $critic = Perl::Critic->new(-severity => 4); sub test { my ($name, $code) = @_; eval $code; @x = @orig; is_deeply ([ &$name(@x) ], \@e, $name); say " ", (eq_array(\@orig, \@x) ? "is NOT mutating" : "is mutating"); # Optional fixups that your Perl::Critic config expects $code = <<"FAKE_CODE"; package Foo; use strict; use warnings; $code; 1; FAKE_CODE say " ", ($critic->critique(\$code) ? "offends Perl::Critic" : "does not offend Perl::Critic"); print " ", $_ for $critic->critique(\$code); } my %compare; for (keys %tests) { my ($name, $code) = ($_, $tests{$_}); test $name => $code; $compare{$name} = sub { @x = @orig; my @y = &$name(@x); }; } cmpthese (1000000, \%compare); done_testing;