Reputation: 95
As the title says, perl adds dummy elements to arrays after inquiries to not existing elements. Array size grows after the inquiry. Illustration to the behaviour:
my $rarr;
$rarr->[0][0] = 'S';
$rarr->[0][1] = 'MD';
$rarr->[1][0] = 'S';
$rarr->[1][1] = 'PRP';
my $crulesref;
$crulesref->[0] = $rarr;
check_rule('aa', 0);
if($rarr->[3][0] == 'M'){ # just check a not existing element
print "m\n";
}
check_rule('bb', 0);
if($rarr->[5][0] == 'M'){ # again: just check a not existing element
print "m\n";
}
check_rule('cc', 0);
sub check_rule($$)
{
my ($strg,$ix) = @_;
my $aref = $crulesref->[$ix];
my $rule_size = @$aref;
{print "-----$strg aref:$aref rs:$rule_size aref:'@$aref'\n";
for(my $t1 = 0; $t1 <$rule_size; $t1++){
print "t1:$t1 0:$aref->[$t1][0] 1:$aref->[$t1][1]\n";
}
}
}
The result of the run is:
en@en-desktop ~/dtest/perl/forditas/utf8_v1/forditas/test1 $ perl v15.pl
-----aa aref:ARRAY(0x90ed8c8) rs:2 aref:'ARRAY(0x9106cac) ARRAY(0x9106d24)'
t1:0 0:S 1:MD
t1:1 0:S 1:PRP
m <-------------- finds the non existing
-----bb aref:ARRAY(0x90ed8c8) rs:4 aref:'ARRAY(0x9106cac) ARRAY(0x9106d24) ARRAY(0x9107508)'
t1:0 0:S 1:MD
t1:1 0:S 1:PRP
t1:2 0: 1: <-- undesired dummy due to inquiry
t1:3 0: 1: <-- undesired dummy due to inquiry
m <-------------- finds the non existing
-----cc aref:ARRAY(0x90ed8c8) rs:6 aref:'ARRAY(0x9106cac) ARRAY(0x9106d24) ARRAY(0x9107904) ARRAY(0x9107508) ARRAY(0x910e860)'
t1:0 0:S 1:MD
t1:1 0:S 1:PRP
t1:2 0: 1: <-- undesired dummy due to inquiry
t1:3 0: 1: <-- undesired dummy due to inquiry
t1:4 0: 1: <-- undesired dummy due to inquiry
t1:5 0: 1: <-- undesired dummy due to inquiry
Is there no other way to avoid this than to ask before each inquiry, if the inquired element exists? I try to increase speed, and these inquiries slow the code down, and make it less easy to read.
Thanks in advance for useful hints.
Upvotes: 6
Views: 233
Reputation: 67900
This is autovivification that you are seeing. If you access the memory of $ref->[3][0]
even with just a check:
if ($ref->[3][0] eq 'M' )
Then first $ref->[3]
must exist before its element number zero can be checked, so it is created via autovivification. You need to first check if $ref->[3]
exists or is defined to avoid creating it.
if (defined($ref->[3]) && $ref->[3][0] eq 'M')
Also, you should always use:
use strict;
use warnings;
Then you would see the warnings
Argument "M" isn't numeric in numeric eq (==) at ...
Use of uninitialized value in numeric eq (==) at ...
The if-clause gives a false positive here because the string 'M'
is converted to a number (0
) because of the context imposed by the numeric equality operator ==
. The LHS value is undef
, which is also converted to a number (0
), which is why the expression evaluates to true.
Upvotes: 12