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 usethe 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::ProhibitDoubleSigilswill 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.