views:

149

answers:

4

Consider this Perl code

my @a=[[1]];

print $a[0][0];


**output**
ARRAY(0x229e8)

Why does it print an ARRAY instead of 1? I would have expected @a to create an array of size 1 with a reference to a second array containing only one element, 1.

+10  A: 

The value that you want is at $a[0][0][0]. You're assigning an array reference as the first element of the @a array.

This is a similar thing:

my @a = 'scalar';

And that will create an array of 1 slot with the string 'scalar' as the sole element. So when you assign a scalar to an array, Perl tries to do what it sounds like you want and create a list of size 1, with the scalar value as the first element.

Also,

my @a = undef;

does the same thing, but the first slot is undef. What you want is

my @a = [1];
Axeman
+14  A: 

This stuff is tricky. You have assigned @a as a list containing a reference to an array that contains a reference to an array, which is one more extra level of indirection than you were expecting.

To get the results you expect, you should have said

@a = ( [ 1 ] );
mobrule
+4  A: 

Here is what I am guessing you wanted to write:

my $x = [[1]]; # reference to anon array containing
               # reference to anon array with one element

print $x->[0][0];

See also Perl Data Structures Cookbook.

Sinan Ünür
I know it doesn't particularly matter, but `$x->[0]->[0]` is my preferred way of putting this.
Dan Beam
@Dan Beam : Why would you want to do that? See http://stackoverflow.com/questions/2475042/nested-dereferencing-arrows-in-perl-to-omit-or-not-to-omit
Zaid
because using just `[]` for both arrays and array refs can lead to confusion, but like I said - it doesn't particularly matter
Dan Beam
+3  A: 

mobrule, Axeman and Sinan have all answered your question: you created a data structure 3 layers deep, instead of 2.

I am surprised that no one suggested using the core Data::Dumper library to help understand data structure questions.

use Data::Dumper;

my @a = [[1]];
print Dumper \@a;

This prints:

$VAR1 = [ [ [ 1 ] ] ];

Your error was using the array reference constructor [] instead of just using parenthesis (or nothing). @a = ([1]);

So, why does Perl have the weird [] and {} syntax for declaring hash and array references?

It comes down to the fact that Perl flattens lists. This means that if you say: @a = (@b, @c); that @a is assigned the contents of @b concatenated with the contents of @c. This is is the same as Python's extend list method. If you want @a to have two elements, you need to force them not to expand. You do this by taking a reference to each array: @a = (\@b, \@c);. This is like Python's append list method.

When you want to create anonymous nested structures you need to have a way to mark them as hashes or arrays. That's where the syntax I mentioned above comes in.

But what good is list flattening? Why is it worth having this unusual syntax for making array and hash references, that is distinct from the syntax used for normal initialization?

List flattening means that you can easily assemble a list of subroutine parameters in a variable and then pass them in without doing anything tricky: foo(@some_args, 5, @more_args);. See Apply on wikipedia for info on how this concept works in other languages. You can do all sorts of other nice things with map and other functions.

daotoad