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?

Fortmann
  • 433
  • 6
  • 20
  • why bother? it really isn't any easier working with `@myArr` than with `$arr_ref` – ysth Jan 23 '14 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.) – tobyink Jan 23 '14 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. – Fortmann Jan 23 '14 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. – ikegami Jan 23 '14 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? – Fortmann Jan 23 '14 at 16:25
  • "cast" is not a perl concept. if $Metric_Config is a reference to a hash, you would just do `$Metric_Config->{'Expression'}{'Operations'}` (or the less popular style `$$Metric_Config->{'Expression'}{'Operations'}`). http://perlmonks.org/?node=References+quick+reference may help you. – ysth Jan 23 '14 at 18:31
  • Yes, it's a hash ref. but Operations points to an array - why work with such a long string when I could be working with something like @arr for the rest of the function? – Fortmann Jan 24 '14 at 08:32

2 Answers2

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);
tobyink
  • 13,478
  • 1
  • 23
  • 35
  • 1
    +1, perhaps mentioninghttp://stackoverflow.com/questions/3603466/how-is-my-faster-than-local-in-perl – mpapec Jan 23 '14 at 10:08
  • Thanks tobyink, that seems to work perfectly: sub test { our @myArr; local *myArr = shift; print join("\n", @myArr); } – Fortmann Jan 23 '14 at 12:04
  • 1
    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. – tobyink Jan 23 '14 at 12:34
  • 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]`. – Mariano Paniga Apr 12 '22 at 16:16
2

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

alexchandel
  • 532
  • 6
  • 15