5
#!/usr/bin/perl -w

use strict;

my $aref = [1, 2, 3];
my @a = @$aref;              # this line
$a[1] = 99;
print "aref = @$aref\n";
print "a = @a\n";

produces output:

aref = 1 2 3
a = 1 99 3

The output shows that @a and @$aref do not refer to the same array.

The marked line is where my problem lies. The value of scalar $aref is a reference to an anonymous array. In the marked line I was hoping to be able to make the array variable @a refer to that array, but what happens is that the anonymous array is copied and @a refers to a copy of the anonymous array. The assignment and print statements show this.

I understand that when you assign to an array the right hand side of the assignment is a list context, so the @$aref is coerced to a list of its elements. Is there a way to give the name @a to the array referred to by $aref?

9
  • 1
    What's wrong with just using @$aref? Commented Jul 29, 2015 at 16:04
  • You can make @a a reference, my $a = $aref Commented Jul 29, 2015 at 16:14
  • 2
    @NormanofAnstruther That's why I left a comment, not an answer. You can often get better answers if you explain why you want to do something instead of just how you want to do it. Commented Jul 29, 2015 at 16:26
  • 2
    it doesn't; he's suggesting you not use @a. despite the alias suggestions given in the answers, that is really your best option. Commented Jul 29, 2015 at 16:27
  • 1
    @NormanofAnstruther: Remember that you generally don't want to refer to the entire array. Individual elements can be referred to as $aref->[1] etc.. The old-fashioned way is ${$aref}[1] (bad) or $$aref[1] (worse). Also note that use warnings is superior in every way to -w on the command line or shebang line Commented Jul 29, 2015 at 16:56

4 Answers 4

7

I wonder why would you want to do this? I presume it's a performance issue, but the usual solution is to pass your data around by reference. It is just as easy to write $aref->[1] as $a[1]

You could alias your reference in the package symbol table by assigning to the typeglob, but the alias must be a package variable

use strict;
use warnings;

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

our @a;
*a = $aref;

$a[1] = 99;

print "aref = @$aref\n";
print "a    = @a\n";

output

aref = 1 99 3
a    = 1 99 3

There are a number of modules that offer a nice syntax and allow you to alias lexical variables

Here's a version that uses Lexical::Alias which has the advantage of aliasing lexical variables, and could be more robust than assigning to typeglobs. Data::Alias works in a very similar way. The output is identical to the above

use strict;
use warnings;

use Lexical::Alias qw/ alias_r /;

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

alias_r $aref, \my @a;

$a[1] = 99;

print "aref = @$aref\n";
print "a    = @a\n";

an alternative way is to use alias instead of alias_r with

alias @$aref, my @a;
Sign up to request clarification or add additional context in comments.

6 Comments

absolutely avoid using the first suggestion in this answer; there is no good reason to use a non-lexical variable when you don't have to.
@ysth: I think absolutely avoid is a little strong. Package variables have lexical scope, and need not be visible everywhere. I wouldn't be certain of choosing a module over, say { our @a; *a = $aref; $a[1] = 99; say "@a"; } if it was necessary. Furthermore there is no choice of lexical identifiers when it comes to subroutines
package variables have lexical scope? that is false. the lexical alias our creates is lexical, but the data is still global with all the potential for clobbering that brings. perl 5.18 introduced (experimental) lexical subs; it's something that people have wanted for a long time.
@ysth: Yes, of course. But I would prefer to put the blame on fully-qualified identifiers than on package variables themselves. I very rarely see package variables qualified with their package name, but then I also rarely see them scoped correctly. Sadly the same applies to lexical variables
You are addressing a side point, not the main point. { our $a; $a .= "a" } { our $a; $a .= "b"; print $a } prints "ab", not "b", as does sub foo { our $a; $a = "ab" } { our $a; $a = "b"; foo(); print $a }. Global variables are a problem even without fully qualified identifiers because they are not scoped.
|
6
  1. our @array; local *array = $aref;
    

    Pros: Built-in feature since 5.6.
    Cons: Ugly. Uses a global variable, so the variable is seen by called subs.

  2. use Data::Alias qw( alias );
    alias my @array = @$aref;
    

    Pros: Clean.
    Cons: This module gets broken by just about every Perl release (though it gets fixed quickly if not before the actual release).

  3. use feature qw( refaliasing );
    no warnings qw( experimental::refaliasing );
    \my @array = $aref;
    

    Pros: Built-in feature.
    Cons: Requires Perl 5.22+, and even then, the feature is experimental.

Comments

1

To expand on Borodin's answer, I've tested this with the Lexical::Alias module:

#!/usr/bin/perl -w

use strict;
use Lexical::Alias 'alias_a';

my $aref = [1, 2, 3];
my @a;
alias_a(@$aref, @a);
$a[1] = 99;
print "aref = @$aref\n";
print "a = @a\n";

Comments

1

One option is to use the Data::Alias package from CPAN.

This way you can write:

#!/usr/bin/perl

use Data::Alias qw( alias );

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

alias my @a = @$aref;

$a[1] = 99;
print "aref = @$aref\n";
print "a = @a\n";

A related question on SO can be found here: Assign address of one array to another in Perl possible?

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.