5

In C#, it is possible to create references to reference types:

SomeObject origObj = new SomeObject();
SomeObject objRef = origObj;

Both origObj and objRef refer to the same object.

Now, in perl:

my @arr = (1,2,3);
method(\@arr);

sub method
{
  my $arr_ref = shift;
  foreach my $element (@{$arr_ref})
  {
     #...
  }
}

I want to work with "@myArr" inside the method, instead of having to cast each time : "@{$arr_ref}" - and to do this without creating a copy of the array (because my "@myArr = @{$arr_ref}" will create a copy).

To Summarize : how can I get "@myArr = @{$arr_ref}" without creating a copy?

7
  • why bother? it really isn't any easier working with @myArr than with $arr_ref Commented Jan 23, 2014 at 10:20
  • 1
    @ysth, in terms of ease there's little difference, but indexing into an array is slightly (about 7%) faster than indexing into an arrayref. (Lexical variables are faster than package variables though, so you only get the benefit of the speed-up using the Data::Alias solution.) Commented Jan 23, 2014 at 10:50
  • Perhaps I need some advice in this regard, but my intention was to improve readability but casting an argument once (immediately), instead of having to cast it multiple times (ever time it is used) within the function code @{$arr_ref}. Performance, I must admit, is not a priority in this case. Commented Jan 23, 2014 at 12:07
  • 2
    @Fortmann, @$objs isn't any less readable than @objs. $objs->[0] isn't any less readable than $objs[0]. What's hindering the readability is all the instances of _ref and needless curlies. Commented Jan 23, 2014 at 15:24
  • Thanks for the tip - In my actual use case I had a complex hash $Metric_Config{'Expression'}{'Operations'}, which points to the array in question. I ended up casting @$Metric_Config{'Expression'}{'Operations'}, but then wanted a simple pointer to the array instead. What would you suggest? Commented Jan 23, 2014 at 16:25

2 Answers 2

8

If you're happy for @myArr to be a package variable (our) rather than a lexical variable (my), you can do:

our @myArr;
local *myArr = $arr_ref;

This will make @myArr act like an alias for the array which $arr_ref is pointing at.

If you need for @myArr to be lexical, then you can use Data::Alias:

use Data::Alias;
alias(my @myArr = @$arr_ref);
Sign up to request clarification or add additional context in comments.

4 Comments

+1, perhaps mentioninghttp://stackoverflow.com/questions/3603466/how-is-my-faster-than-local-in-perl
Thanks tobyink, that seems to work perfectly: sub test { our @myArr; local *myArr = shift; print join("\n", @myArr); }
One thing you should be aware of with package variables is that they're globals (albeit namespaced ones). So if your test() sub were to call another sub, that other sub could also access @myArr. Using lexicals is generally preferable, as it allows you to eliminate a source of "spooky action at a distance". For that reason, I'd personally prefer the Data::Alias solution over the package variable. However, Data::Alias is a non-core module that uses some very funky techniques internally; it has (in recent history) been broken on certain versions of Perl for significant periods of time.
In my case "Data::Alias" libary is not present on the system, I resolved my needs using syntax suggested by @ikegami in the above comments (the ones under the question): @{$array_ref} in place of @array, and $array_ref->[0] in place of $array[0].
3

Perl 5.22 added "refaliasing" or assigning to references, which does exactly what you want:

no warnings qw(experimental);
use feature qw(refaliasing);

my $a = [1, 2, 3];

\my @b = $a; # a & b are the same array

my @c;
\@c = $a; # a, b, & c are the same array

push @b, 4;
push @c, 5;

print "@$a\n"; # prints 1 2 3 4 5

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.