Question

In perl, it's possible to work with hashes, e.g. my %a = (2, "two"); as well as hashrefs, e.g. my $b = {2 => "two"};

Whenever I create a multidimensional hash, the values of the top-level hash are always hashrefs, i.e. calling ref() on them returns "HASH". Is it possible to have a hash of mere hashes, without the extra level of indirection?

Additionally, when working with a hash of hashes, perl allows one to omit the dereference operator when accessing an element of the child hash:

my %a;
$a{2} = {2 => "two"};

# the following are both valid:
$a{2}->{2}
$a{2}{2}

I assume that the second is just syntactic sugar for the first. However, this seems inconsistent with the syntax required for a simple un-nested hashref, as $b->{2} is valid whereas $b{2} is not.

My reason for asking is that I'd like to be able to say

for my %hash (values %a) { 

or even

for my %hash (map(%{$_}, values %a)) {

but both of these cause a "Missing $ on loop variable" error at compile time.

Was it helpful?

Solution

In the beginning, there were only scalars, hashes, and arrays. Actually, that was Perl4, but when Perl5 was being designed, absolute backwards compatibility was a key point. This means that $hash{entry} = @array would have to keep assigning the array size to that hash entry rather than putting the array into the hash. So collections can only contain scalars.

This is one of the main reasons why references were needed – hash references and array references allow us to refer to a collection as a single scalar thing. The syntax for hash references needs to be different from that of hashes. The dereference arrow -> (borrowed from C) can be used for a hashref access: $hashref->{entry}. Because hashes can never contain a collection directly, the dereference arrow between subscripts is unnecessary for disambiguation between hashes and hashrefs, so $ref->{a}->{b} and $ref->{a}{b} do the same thing. However, hashref accesses cannot use $ref{entry} because that syntax is already in use for hash accesses, as both $name and %name can exist at the same time as separate variables.

So in short, the syntax is ugly, but for good backwards compatible reasons.

Currently, for my %hash (@hash_references) or for my @array (@hash_references) aren't allowed as far as I'm aware. I personally don't see any issues with this syntax, but implicit dereferencing is admittedly rather confusing. Having to use %$ref rather than %hash isn't really that bad.

By the way, Perl6 got rid of references, because this difference between hashes and hashrefs is quite unnecessary aside from backwards compatibility. Collection variables behave more like scalars, although there are new contexts like an “item context” to help with the lack of references.

OTHER TIPS

No, hash values are always scalars. Hashes and arrays are not scalars, so cannot be hash values, but references to them are scalars, so can be hash values.

The first paragraph of the perldata documentation page says (my emphasis):

Perl has three built-in data types: scalars, arrays of scalars, and associative arrays of scalars, known as "hashes". A scalar is a single string (of any size, limited only by the available memory), number, or a reference to something (which will be discussed in perlref). Normal arrays are ordered lists of scalars indexed by number, starting with 0. Hashes are unordered collections of scalar values indexed by their associated string key.

Is it possible to have a hash of mere hashes, without the extra level of indirection?

No. Other languages implicitly do what you ask, but on the other hand they don't have scalar and list context which can be found in perl.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top