3

There is a similar question How can I assign the result of a subroutine call to array references in Perl? but I'm curious about perl's possibilities

Is there a hack in perl to directly dereference element-wise an array of references?

in a code like

sub test { return([1..4],[5..8]); }
my (@a,@b);
my @result = test();
@a = @{$result[0]}; @b = @{$result[1]};

I would like to shorten the code to a simple statement like

sub test { return([1..4],[5..8]); }
my (\@a,\@b) = test();

or in a loop

foreach my $element (\"1",\"2",\"3") {
    my $dereferenced_element = $$element;

it would be nice to write something like

foreach my \$element (\"1",\"2",\"3") {

I know that this syntax doesn't make much sense, as I don't want to assign a value to the reference of a variable, but to assign a dereferenced value to the variable itself
but I'm curious if there is anything in that direction in perl's repertoire and I think this example shows the best, what I'm intending to do

Community
  • 1
  • 1
Hachi
  • 3,237
  • 1
  • 21
  • 29

4 Answers4

3

You can modify the globes directly if you want, but that is not a good practice.

sub test { return [1..3], [2..4]; }
(*x, *y) = test;
print "@x and @y";

Output:

1 2 3 and 2 3 4

This doesn't work with lexical (my) variables. To make it work with strict, you can declare the variables with our (instead of my).

Qtax
  • 33,241
  • 9
  • 83
  • 121
  • +1 this is a very nice possibility; if no answer is coming closer to what I want, I'll accept this as answer – Hachi Mar 26 '12 at 09:04
2

This is not answering your question regarding the direct de-referencing but

what you are doing in:

sub test { return([1..4],[5..8]); }
my (@a,@b);
my @result = test();
@a = $result[0]; @b = $result[1];

is not entirely correct, your @a and @b arrays become 2d arrays after this.

Instead you should say:

@a = @{$result[0]};
@b = @{$result[1]};

or, as you most probably already know:

my ($a, $b) = test();

or:

for my $element (test()) {
     # $element is an array ref
}
Nylon Smile
  • 8,990
  • 1
  • 25
  • 34
1

@Qtax answer is neat. I was wondering else it could be done. Not exactly what you asked for, but near.

sub test { return [1..3], [2..4]; }

my (%a);

@a{'ret1','ret2'} = test();

print @{$a{'ret1'}} ;
print @{$a{'ret2'}} ;
tuxuday
  • 2,977
  • 17
  • 18
0

The best way, IMO, is to assign the array refs to scalar variables, and dereference them as needed.

my ($x, $y) = test();

my @arrayx = @$x;
my @arrayy = @$y;

print "Element 1 in \$x is: $x->[1]\n";
for my $element (@$x) { ... }

You should also be aware that using $a and $b as variables is a bad idea, because they are predefined global variables used by the sort routine. They can be used, like most predefined variables, but it may lead to strange behaviour and hard to find bugs.

TLP
  • 66,756
  • 10
  • 92
  • 149
  • I agree that this is the most reasonable way, but I was curious about the possibilities; $a,$b here are just for an example; in practice I use speaking names – Hachi Mar 26 '12 at 13:03
  • @Hachi There is no mystery here. You are returning a list of two scalar arguments. You can assign them to scalars or dereference them into arrays. That's it. The global solution with `*a` relies on bending the rules, and is not really much different than using an intermediate scalar `$x = test(); @x = @$x`. Using global values is not something I'd recommend in order to save yourself some typing. – TLP Mar 26 '12 at 14:28