Perl v5.22’s experimental refaliasing
feature adds the ability to alias a named variable to another named variable, or alias a named variable to a reference. This doesn’t copy the data; you end up with another named variable for the same data. As with all such features, the details and syntax may change or the feature may be removed all together (according to perlpolicy). Update: Also see v5.26’s declared_refs
experimental feature.
Remember that variables are labels for data somewhere (and in Perl we aren’t supposed to care about that somewhere). We use the variable name in our code and Per handles the details of finding and using the right data. This experimental feature allows you to add a new label that’s a named variable.
Review what you can already do. Take a reference to the named variable:
my @animals = qw(Buster Mimi Addy); my $animals_ref = \@animals
This isn’t a copy. It’s the same data with two different references. The Devel::Peek module can expose some of these details. Remember that the stringified reference has a (mostly useless to you) memory address:
use Devel::Peek; my @animals = qw(Buster Mimi Addy); Dump( @animals ); my $animals_ref = \@animals; warn "$animals_ref"; Dump( @animals );
The output shows Perl’s memory address for the data. In the first part of the output you see REFCNT = 1
. At the point of the first Dump
only @animals
connects to the data. In the middle output, you see that the reference memory address is the matches one of the numbers in the Dump
output (and that’s all you’ll read about that here). In the last part of the output you see that there’s another reference to the same data (REFCNT = 1
):
SV = PVAV(0x7fc78d803f48) at 0x7fc78d81b390 REFCNT = 1 FLAGS = () ARRAY = 0x7fc78cd00f20 -------- ARRAY(0x7fc78d81b390) at /Users/brian/Desktop/test3.pl line 16. -------- SV = PVAV(0x7fc78d803f48) at 0x7fc78d81b390 REFCNT = 2 FLAGS = () ARRAY = 0x7fc78cd00f20 ...
You can skip the named variable to create the reference directly:
my $animals_ref = [ qw(Buster Mimi Addy) ];
Prior to v5.22, there wasn’t a built-in way to go from that reference to a named variable. You could get the same data in the named variable but it would be different data. The Data::Alias and Lexical::Alias modules could do it, but then you have another dependency.
ref_aliasing
lets you go from one named variable to another so that both are labels for the same data. Changing one “changes” the other because they are same data:
use v5.22; use feature qw(refaliasing); no warnings qw(experimental::refaliasing); my @animals = qw(Buster Mimi Addy); \my @pets = \@animals; $pets[0] = 'Ginger'; say $animals[0]; # Ginger
The my
isn’t magical here. You can still alias the named variables after you declare them:
use v5.22; use feature qw(refaliasing); no warnings qw(experimental::refaliasing); my @animals = qw(Buster Mimi Addy); my @pets; \@pets = \@animals; $pets[0] = 'Ginger'; say $animals[0]; # Ginger
The most compelling case may be iterating through a list of references. The control variable must be a scalar. A foreach
could alias a reference value to it but you still have to dereference it. This is handy when you want to reduce dereferencing inside your block:
use v5.22; use feature qw(refaliasing); no warnings qw(experimental::refaliasing); my @hash_refs = ( { name => 'Buster', type => 'cat' }, { name => 'Mimi', type => 'cat' }, { name => 'Addy', type => 'dog' }, ); foreach \my %hash ( @hash_refs ) { say $hash{'name'}; # otherwise it's $hash->{'name'} }
The output shows each animal’s name:
Buster Mimi Addy
Looking ahead to signatures
Sometime in the future you can imagine this being part of the (also experimental) subroutine signatures to pass data structure references into named parameters:
some_task( \@array, \%hash ); sub some_task ( \@a, \%h ) { ... }
You can still get this with conventional argument handling by using the reference operator before the declaration (the my
). Remember that you aren’t taking a reference to a list. Instead, the reference operator (\
) distributes through the list:
use v5.22; use feature qw(refaliasing); no warnings qw(experimental::refaliasing); use Data::Dumper; my @names = qw( Ginger Addy Buster ); my %types = ( 'Ginger' => 'cat', 'Addy' => 'dog', ); some_task( \@names, \%types ); sub some_task { \my( @a, %h ) = @_; # \ distributes, not a single ref say Dumper( \@a, \%h ); }
Don’t get too excited: these are experimental features. Fingers crossed though!
Note: this was updated in v5.26’s declared_refs
experimental feature that allows you to declared the references singly:
use v5.26; use feature qw(refaliasing declared_refs); no warnings qw(experimental::refaliasing experimental::declared_refs); sub some_task { my( \@a, \%h ) = @_; # \ distributes, not a single ref say Dumper( \@a, \%h ); }
Things to remember
- The
refaliasing
feature is experimental, so it might change or disappear - You can alias a reference to a named variable
- You can alias a named variable to another named variable.