4

I have the following code:

my @array = ('a', 'b', 'c');

my $region = \@array;  # Returns an array reference
my $Value = ${@{$region}}[3];   

I am using strict;

This code passed smoothly in Perl v5.8.6, and now that I installed v5.10.1, I get a runtime error:

Can't use string ("4") as an ARRAY ref while "strict refs" in use at ...

I changed the code to the following, and that solved the issue:

my @array = ('a', 'b', 'c');

my $region = \@Array;
my @List = @{$region};
my $Value = $List[3];   

my question is, what's wrong with the previous way? What has changed between these two versions? What am I missing here?

Thanks, Gal

Gal Goldman
  • 8,641
  • 11
  • 45
  • 45
  • 5
    Also what I think the problem is... that your region contains 4 elements, than @{$region} is evaluated in a list context which returns 4 and your call becomes: $Value = ${'4'}[3] which produces the error – Dimitar Petrov Aug 14 '11 at 10:56
  • 2
    Why do you keep referencing the 4th element in a list which is three elements long in the code? – Conspicuous Compiler Aug 14 '11 at 11:29

2 Answers2

11

${@{$region}}[3] was never the correct way to access an arrayref. I'm not quite sure what it does mean, and I don't think Perl is either (hence the different behavior in different versions of Perl).

The correct ways are explained in perlref:

my $Value = ${$region}[3]; # This works with any expression returning an arrayref
my $Value = $$region[3];   # Since $region is a simple scalar variable,
                           # the braces are optional
my $Value = $region->[3];  # This is the way I would do it
cjm
  • 61,471
  • 9
  • 126
  • 175
  • 2
    The new behavior is correct; the block after the `$` should get scalar context. Older perl versions would erroneously promote the array to an array reference. But I thought this was going through a deprecation cycle - looks like that was done for `@array->[]` but not `${@array}[]` :( – ysth Aug 14 '11 at 12:05
  • `${ @{$region} }[3]` is `${ scalar(@{$region}) }[3]`. It's equivalent to `$0[3]`, `$1[3]`, `$2[3]` or similar, depending on the number of elements in `@$region`. – ikegami Aug 14 '11 at 21:18
  • @Jared Ng, All *3*? Only two ways were presented. If you consider adding parens, then there are far more than 3. `${$region}[3]`, `${region}->[3]` and `($region)->[3]`, for starters. – ikegami Aug 14 '11 at 21:20
  • @ysth, Those curlies don't form a block. – ikegami Aug 14 '11 at 21:22
  • @ysth, as best I can tell, `${@array}[]` didn't get a deprecation cycle cause it always worked correctly. (Worked in 5.10, don't have 5.8 anymore) `@array->[]` was deprecated in 5.12 and fixed in 5.14. – ikegami Aug 14 '11 at 21:25
  • ikegami: yes, they do. `print for %{ my %x; @x{"a".."j"} = reverse 0..9; \%x }` – ysth Aug 14 '11 at 21:27
  • @ysth, hum, My test must have been bad, sorry. – ikegami Aug 14 '11 at 23:08
2

This is how I would do it:

my @array = ('a', 'b', 'c');
my $region = \@array;
my $Value = $$region[1];
print $Value;

Output:

b
Jared Ng
  • 4,891
  • 2
  • 19
  • 18