[ Team LiB ] Previous Section Next Section

4.5 Creating an Anonymous Array Directly

In the get_provisions_list routine earlier, you created a half dozen array names that were used only so that you could take a reference to them immediately afterward. When the subroutine exited, the array names all went away, but the references remained.

While creating temporarily named arrays would work in the simplest cases, creating such names becomes more complicated as the data structures become more detailed. You'd have to keep thinking of names of arrays just so you can forget them shortly thereafter.

You can reduce the namespace clutter by narrowing down the scope of the various array names. Rather than letting them be declared within the scope of the subroutine, you can create a temporary block:

my @skipper_with_name;
{
  my @skipper = qw(blue_shirt hat jacket preserver sunscreen);
  @skipper_with_name = ("The Skipper", \@skipper);
}

At this point, the second element of @skipper_with_name is a reference to the array formerly known as @skipper. However, the name is no longer relevant.

This is a lot of typing to simply say "the second element should be a reference to an array containing these elements." You can create such a value directly using the anonymous array constructor, which is Yet Another Use for square brackets:

my $ref_to_skipper_provisions =
  [ qw(blue_shirt hat jacket preserver sunscreen) ];

The square brackets take the value within (evaluated in a list context); establish a new, anonymous array initialized to those values; and (here's the important part) return a reference to that array. It's as if you said:

my $ref_to_skipper_provisions;
{
  my @temporary_name =
  ( qw(blue_shirt hat jacket preserver sunscreen) );
  $ref_to_skipper_provisions = \@temporary_name;
}

Here you don't need to come up with a temporary name, and you don't need the extra noise of the temporary block. The result of a square-bracketed anonymous array constructor is an array reference, which fits wherever a scalar variable fits.

Now you can use it to construct the larger list:

my $ref_to_skipper_provisions =
  [ qw(blue_shirt hat jacket preserver sunscreen) ];
my @skipper_with_name = ("The Skipper", $ref_to_skipper_provisions);

Of course, you didn't actually need that scalar temporary, either. You can put a scalar reference to an array as part of a larger list:

my @skipper_with_name = (
  "The Skipper",
  [ qw(blue_shirt hat jacket preserver sunscreen) ]
);

Now let's walk through this. You've declared @skipper_with_name, the first element of which is the Skipper's name string, and the second element is an array reference, obtained by placing the five provisions into an array and taking a reference to it. So @skipper_with_name is only two elements long, just as before.

Don't confuse the square brackets with the parentheses here. They each have their distinct purpose. If you replace the square brackets with parentheses, you end up with a six-element list. If you replace the outer parentheses (on the first and last lines) with square brackets, you construct an anonymous array that's two elements long and then take the reference to that array as the only element of the ultimate @skipper_with_name array.[2]

[2] In classrooms, we've seen that too much indirection (or not enough indirection) tends to contribute to the most common mistakes made when working with references.

So, in summary, the syntax:

my $fruits;
{
  my @secret_variable = ('pineapple', 'papaya', 'mango');
  $fruits = \@secret_variable;
}

can be simply replaced with:

my $fruits = ['pineapple', 'papaya', 'mango'];

Does this work for more complicated structures? Yes! Any time you need an element of a list to be a reference to an array, you can create that reference with an anonymous array constructor. In fact, you can also nest them in your provisions list:

sub get_provisions_list {
  return (
    ["The Skipper",
      [qw(blue_shirt hat jacket preserver sunscreen)]
    ],
    ["The Professor",
      [qw(sunscreen water_bottle slide_rule batteries radio)]
    ],
    ["Gilligan",
      [qw(red_shirt hat lucky_socks water_bottle)]
    ],
  );
}

my @all_with_names = get_provisions_list(  );

Walking through this from the outside in, you have a return value of three elements. Each element is an array reference, pointing to an anonymous two-element array. The first element of each array is a name string, while the second element is a reference to an anonymous array of varying lengths naming the provisions—all without having to come up with temporary names for any of the intermediate layers.

To the caller of this subroutine, the return value is identical to the previous version. However, from a maintenance point of view, the reduced clutter of not having all the intermediate names saves screen and brain space.

You can show a reference to an empty anonymous hash using an empty anonymous array constructor. For example, if you add one "Mrs. Howell" to that fictional travel list, as someone who has packed rather light, you'd simply insert:

["Mrs. Howell",
  [  ]
],

This is a single element of the larger list. This item is a reference to an array with two elements, the first of which is the name string, and the second of which is itself a reference to an empty anonymous array. The array is empty because Mrs. Howell hasn't packed anything for this trip.

    [ Team LiB ] Previous Section Next Section