This is a chapter in Perl New Features, a book from Perl School that you can buy on LeanPub or Amazon. Your support helps me to produce more content.
Perl v5.36 disables by default a Perl 3 feature that you may have never seen, which I’ll cover in the next section. In a single-element access to a hash, you were able to use a list of indices to simulate a multidimensional data structure. This was long before Perl had references (and shortly before Taylor Swift was born). Yet, in v5.34, this still works:
use v5.34; my %hash; $hash{1,3} = 7; # modern way is $array[1][3] = 7;
In v5.36, this still works as long as you specify a minimum Perl version with require
instead of use
:
require v5.36; my %hash; $hash{1,3} = 7;
With use
, though, Perl loads the appropriate feature bundle, which turns off this feature:
use v5.36; my %hash; $hash{1,3} = 7;
The output shows that the multidimensional
feature was removed from the list:
Multidimensional hash lookup is disabled at ... Execution of ... aborted due to compilation errors.
This version also disables switch
and indirect
.
Enable multidimensional
explicitly if you want to restore it, although you should only do this for legacy code since the feature is likely disappear completely:
use v5.36; use warnings; use feature qw(multidimensional);
Perl 4’s fake multidimensional hashes
Perl 4 did not have references, so it didn’t have a way include an array in an array. However, you could fake it with a special hash
key convention that Perl stole from Awk.
To make this work, you access a single element in the hash, but have a “list” of comma-separated index values as the hash key:
my %hash; $hash{0,0} = "a"; $hash{1,1} = "b"; for( my $row = 0; $row <= 1; $row++ ) { for( my $col = 0; $col <= 1; $col++ ) { printf '% 2s', $hash{$row,$col} // 0; } print "\n"; }
This outputs your tiny matrix:
a 0 0 b
To see what Perl is doing, dump that hash. The $Useqq
variable from Data::Dumper encodes unprintables as their ordinal values in octal"
$Data::Dumper::Useqq = 1; say Dumper(\%hash);
$VAR1 = { "0\0340" => "a", "1\0341" => "b" };
That \034
is (U+001C INFORMATION SEPARATOR FOUR):
printf '% 2s', $hash{ "$row\034$col" } // 0;
Perl calls that $;
(or $SUBSCRIPT_SEPARATOR
or $SUBSEP
). Larry had wanted to use $,
but that was already the output field separator. You can use this value directly:
printf '% 2s', $hash{ "$row$;$col" } // 0;
You can mix the forms too. This examples assigns with the comma notation but outputs it by constructing the key itself:
$row = 1; $col = 3; $hash{$row,$col} = 7; printf '% 2s', $hash{ "$row$;$col" } // 0;
Change the separator
If \034
is something that might appear in your data, change the multidimensional separator to something that won't conflict:
local $; = '\000'