Create named variable aliases with ref aliasing

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.
Leave a comment

0 Comments.

Leave a Reply


[ Ctrl + Enter ]