1

Just starting with Perl, and I used the wrong pair of parentheses for this code example:

@arr = {"a", "b", "c"};
print "$_\n" foreach @arr;

I mean, I can of course see WHAT it does when I run it, but I don't understand WHY it does that. Shouldn't that simply fail with a syntax error?

jackthehipster
  • 978
  • 8
  • 26
  • 5
    Welcome to perl. Always include [`use strict;`](http://perldoc.perl.org/strict.html) and [`use warnings;`](http://perldoc.perl.org/warnings.html) at the top of EVERY perl script. In this instance, you would've gotten the warning `Odd number of elements in anonymous hash` which could've also clued you in to the mistype. – Miller Aug 06 '14 at 13:58
  • 3
    @Miller: Unless the OP added a fourth element, in which case perl would proceed silently. – Michael Carman Aug 06 '14 at 14:12
  • 1
    @Miller: And *always* spell it *Perl* ;) – Borodin Aug 06 '14 at 14:28
  • @Borodin: Unless you're talking about the interpreter (as I was). :) http://stackoverflow.com/questions/72312/how-should-i-capitalize-perl – Michael Carman Aug 06 '14 at 14:46
  • @Borodin, "perl" is proper if you are referring to the program/executable. – ikegami Aug 06 '14 at 14:48
  • @MichaelCarman, @ikegami: My remark was a light-hearted one, as evidenced by the `;)`, and was addressed to @Miller. In any case `perlfaq1` says *"You may or may not choose to follow this usage"*, and because the line between language and interpreter can often be blurred I use *Perl* pretty much universally. *perl* is clearly wrong for the language as it is a proper name, and *PERL* is just as wrong because it is not a (real) acronym – Borodin Aug 06 '14 at 14:58

3 Answers3

3

You have accidentally created an anonymous hash, which is a hash that has no identifier and is accessed only by reference.

The array @arr is set to a single element which is a reference to that hash. Properly written it would look like this

use strict;
use warnings;

my @arr = (
  {
    a => "b",
    c => undef,
  }
);

print "$_\n" foreach @arr;

which is why you got the output

HASH(0x3fd36c)

(or something similar) because that is how Perl will represent a hash reference as a string.

If you want to experiment, then you can print the value of the first hash element by using $arr[0] as a hash reference (the array has only a single element at index zero) and accessing the value of the element with key a with print $arr[0]->{a}, "\n".

Note that, because hashes have to have a multiple of two values (a set of key/value pairs) the hash in your own code is implicitly expanded to four values by adding an undef to the end.

It is vital that you add use strict and use warnings to the top of every Perl program you write. In this case the latter would have raised the warning

Odd number of elements in anonymous hash
Borodin
  • 126,100
  • 9
  • 70
  • 144
  • Thanks. Your answer also explains why @arr is still an array, even though it was initialized as a hash. – jackthehipster Aug 06 '14 at 14:55
  • It wasn't initialized as a hash. 1) As I explained, `{}` returns a scalar, and you can definitely assign a list of scalars to an array. (e.g. `my @a = ('a');`) 2) That would be wrong to assign to hash. – ikegami Aug 06 '14 at 14:55
3

It can be surprising how few things are syntax errors in Perl. In this case, you've stumbled onto the syntax for creating an an anonymous hash reference: { LIST }. Perl doesn't require the use of parentheses (the () kind) when initializing an array1. Arrays hold ordered lists of scalar (single) values and references are scalars so perl happily initializes your array with that reference as the only element.

It's not what you wanted, but it's perfectly valid Perl.

The () override the precedence of the operators and thus changes the behavior of the expression. @a = (1, 2, 3) does what you'd expect, but @a = 1, 2, 3 means (@a = 1), 2, 3, so it only assigns 1 to @a.

Michael Carman
  • 30,628
  • 10
  • 74
  • 122
2

{ LIST } is the hash constructor. It creates a hash, assigns the result of LIST to it, and returns a reference to it.

my $h = {"a", "b", "c", "d"};
say $h->{a};  # b

A list of one hash ref is just as legit as any other list, so no, it shouldn't be a syntax error.

ikegami
  • 367,544
  • 15
  • 269
  • 518