venerdì 5 maggio 2017

perlcritic and allowing simple double sigils dereferencing

I found out, while not searching for it, an interesting policy for Perl::Critic
named Perl::Critic::Policy::References::ProhibitComplexDoubleSigils. The idea is quite simple and I find myself agreeing with it:
when dereferencing a reference you can omit braces; while this is often not a good habit (because it can become
quite difficult to read a complex reference), it can work out on simpler cases:



#!env perl
use v5.20;

my %hash = (
    key1 => "value1"
    , key2 => "value2"
    , key3 => "value3"
    );

my $hash_ref = \%hash;

while ( my ( $k, $v ) = each %$hash_ref ){
    say "$k --> $v";
}

In the above code it is quite simple to understand that @$hash_ref refers to the whole hash without the need to use
the braces around.


I recognize the advantages of using the braces as:

  • a good habit;
  • a way to do a good refactoring in the case the reference points to a multidimensional structure.

Anyway simple idioms should stay simple and so should the checkers manage them.
If I run perlcritic against the above piece of code, the Perl::Critic::Policy::References::ProhibitDoubleSigils
will report


% perlcritic --single-policy=ProhibitDoubleSigils p.pl
Double-sigil dereference at line 12, column 30.  See page 228 of PBP.  (Severity: 2)

Now, using the above mentioned Perl::Critic::Policy::References::ProhibitComplexDoubleSigils the result becomes:


% perlcritic --single-policy=ProhibitComplexDoubleSigils p.pl
p.pl source OK

Ok, let's refactor the program and transform the plain hash in a multidimensional one:




#!env perl
use v5.20;

my %hash = (
    key1 => "value1"
    , key2 => "value2"
    , key3 => "value3"
    );

my %outer_hash = ( config1 => \%hash );
my $hash_ref = \%outer_hash;

while ( my ( $k, $v ) = each %{ $hash_ref->{config1} } ){
    say "$k --> $v";
}

The above part is the right way of dereferencing the reference to the inner hash, and it does use curly braces
and makes Perl::Critic, both policies, not complaining at all.


If, instead, we pretend to use double sigils (that is removing the arrow operator) the code becomes:



#!env perl
use v5.20;

my %hash = (
    key1 => "value1"
    , key2 => "value2"
    , key3 => "value3"
    );

my %outer_hash = ( config1 => \%hash );
my $hash_ref = \%outer_hash;

while ( my ( $k, $v ) = each %{ $$hash_ref{config1} } ){
    say "$k --> $v";
}

and of course both policies complain about:


% perlcritic --single-policy=ProhibitDoubleSigils p.pl
Double-sigil dereference at line 13, column 33.  See page 228 of PBP.  (Severity: 2)

% perlcritic --single-policy=ProhibitComplexDoubleSigils p.pl
Complex double-sigil dereferences at line 13, column 33.  Found complex double-sigil dereference without curly braces.  (Severity: 2)


Something similar happens when you try to extract a single scalar value from the nested hash:



...
# line 20
my $k1 = $$hash_ref{ config1 }->{ key1 };
say "key1 is $k1";

# line 23
$k1 = $hash_ref->{ config1 }->{ key1 };
say "key1 is $k1";

both the above instructions place the correct value into the $k1 variable, and the policies both complain about the first line
(the one with the $$):


% perlcritic --single-policy=ProhibitDoubleSigils p.pl
Double-sigil dereference at line 20, column 10.  See page 228 of PBP.  (Severity: 2)

% perlcritic --single-policy=ProhibitDoubleComplexSigils p.pl
The value for the global "single-policy" option ("ProhibitDoubleComplexSigils") did not match any policies (in combination with other policy restrictions).


Summing up the idea is to allow double sigils only when you are dereferencing a single level, not for complex data structures.

Nessun commento: