3

I have the following code, in which I have a structure ($node) that is a scalar by declaration, but seems to be a hash by usage:

sub LoadData()
 {
     #not significant code here

     my $node = {
                    BaseName => "deviceA",
                    SysDescr => "Example device",

                    SysObjectId => "SysObjectIdTest",

                    ManagementIpAddress => "BLABLABLA",
                    Protocol => "1",

               };

     $store->AddDeviceData( 1, $node->{BaseName}, $node );
 }  

My question is: that $node, declared as we see above, is an hash or a scalar? I mean, is there a difference (in terms of beahvior) between

my $hash = {
    #some foo => "bar" assign here
};

and

my %hash = (
   #some foo => "bar" assign here
);

and

 my %hash = {
   #some foo => "bar" assign here
}

PS: it behaves as an hash reference because AddDeviceData() restricts the last argument to be an hash reference.

PSS: Maybe it had something related to context; an hash being assigned to a scalar means assigning a reference to the hash and not the content of the hash itself, but I´m not pretty sure.

dukibas
  • 35
  • 1
  • 4
  • 1
    It sounds like much of your code has been written using subroutine protoypes, which are not the utility that they are in most languages and should be confined to very specific uses. Furthermore, a normal Perl lexical variable should be named using lower-case letters, digits and underscore: Capital letters are reserved for global identifiers. – Borodin Apr 07 '15 at 13:58
  • @Borodin Thanks for the insight, on both topics. The first point, about prototypes, I will look foward on those specific usages. About the lexical variables it´s just an old costume for me. Will remember this next time. By the way this sample code isn´t mine, it´s from some former fellow from my workplace. I´m just studiyng and modifying to learn those Perl nuances. – dukibas Apr 07 '15 at 14:19
  • That's fair. I assumed that it was worse than that, and you were working in an environment where Perl identifiers and subroutine prototypes were like that as standard. Prototypes are used in modules that are intended to add new operators to the language that work like built-in functions. You can see them used in [the source of `List::UtilsBy`](https://metacpan.org/source/PEVANS/List-UtilsBy-0.09/lib/List/UtilsBy.pm). And I wouldn't take too much notice of the work of your colleague I'm afraid: anyone who uses subroutine prototypes in a Perl program isn't very au fait with the language – Borodin Apr 07 '15 at 14:32
  • Lesson learned. Found this previous topic about this subject, if anyone new to Perl as I am would like to read more about it: [Why are Perl 5's function prototypes bad?](http://stackoverflow.com/questions/297034/why-are-perl-5s-function-prototypes-bad) – dukibas Apr 07 '15 at 14:57

3 Answers3

6

All three of the examples you present behave differently:

my $hash = {
    foo => "bar",
};

creates a hash reference with a single key foo and value bar and assigns it to a scalar named $hash. Values in hash references are accessed by using the arrow operator (->) followed by curly braces and the name of the key; e.g. $hash->{foo}; # bar

my %hash = (
   foo => "bar",
);

creates a hash with single key foo and value bar. Values in hashes are accessed with curly braces and the name of the key; e.g. $hash{foo}; # bar

my %hash = {
   foo => "bar",
}

attempts to assign a hash reference to a hash, which effectively makes the anonymous hash reference the key. Since all hash keys in Perl are strings, the key will be something like 'HASH(0x7f82948e1e18)' with a value of undef. If you have use warnings; enabled (as you should), you would see the following warning when this line is executed:

Reference found where even-sized list expected at test.pl line [line-number].

It might be useful to read the documentation for Perl references: perldoc perlref

Hunter McMillen
  • 59,865
  • 24
  • 119
  • 170
1

The { key => value } syntax is an anonymous hash reference constructor. References are scalars (they're basically fancy pointers) so that's why it's assigned to a scalar variable. As you noticed in the code example you pointed, to get at the data in the underlying hash, you need to use the dereference operator ->. To get at the entire underlying hash, you can use %$node.

For a gentle introduction to Perl references, see the Perl References Tutorial.

friedo
  • 65,762
  • 16
  • 114
  • 184
1

I mean, is there a difference (in terms of behavior) between

my $hash = {
    #some foo => "bar" assign here
};

and

my %hash = (
   #some foo => "bar" assign here
);

and

my %hash = {
   #some foo => "bar" assign here
}
  • my %hash creates a named lexical hash, which can be initialised — separately or in the declaration — with an even-numbered list of key/value pairs. Every key must be a simple string, and every value behaves as a Perl scalar variable

  • The { ... } construct, depending on context, creates an anonymous hash, and evaluates a reference to that hash — a scalar value that can be assigned to a scalar variable. The braces may contain an even-numbered list of key/value pairs that initialise data within the anonymous hash

  • The statement my %hash = { foo => "bar" } is a misconstruction. my %hash creates a named hash, as in the first instance above, while { foo => "bar" } creates another, anonymous hash, as in the second case. The anonymous hash reference forms a single-element list, and is stringified to create the key of an element of %hash. A value of undef is supplied for the missing value. It is similar to

    my %anon = ( foo => 'bar' );
    my %hash - (\%anon, undef);
    

but because of the stringification, the key is something like HASH(0x633444) and cannot be used to access %anon

An element of an anonymous hash can be accessed in two ways. For example, given

my $href = { foo => 'bar' }

the old-fashioned way is to use the reference as if it were a hash name

$$href{foo}

or, identical but clearer

${$href}{foo}

or there is a newer arrow dereference operator that works the same as in the C language and is generally preferred

$href->{foo}
Borodin
  • 126,100
  • 9
  • 70
  • 144
  • Thanks and to @hunter-mcmillen as well. `Reference found where even-sized list expected at` ... explaining common or rare errors that are the "opposite of a bug" (*i.e.* when perl is right even when it is wrong) is a great way to figure out the mechanics of the language and arguably more useful than decoding "Obfuscated Perl". – G. Cito Apr 07 '15 at 14:44