Search code examples
perlaliasperl-module

how to create perl aliases? typeglobs?


Suppose I'm manipulating a hash that's in another package, and I want to create an alias to that variable? What's a clean way to do that? This sample code shows what I want to do, but it, and a dozen variations of it malfunction.

#!/usr/bin/perl
#use strict;  # I want it to work with strict.

my $p = Person->new("Joe");
my $name;
*name = \*$p->{"name"};     # Latest broken attempt

printf("'%s' should eq '%s' because they both point to the same place.\n",
       $name, $p->{"name"});

$name = "Sam";

printf("'%s' should eq '%s' because they both point to the same place.\n",
       $name, $p->{"name"});
exit 0;


package Person;

sub new {
    my $class = shift;

    my $this = {};
    bless $this, $class;

    $this->{"name"} = shift;

    return $this;
}

The functionality I want is to be able to manipulate $p->{"name"} dozens of times without having to type $p->{"name"} repeatedly. The real data structure is far more complex with a lot of nested hashes.

It's probably something easy. Thanks.


Solution

  • The easiest way is to make a copy:

    use strict;
    use warnings;
    my $p = { name => "Joe" };
    my $name = $p->{name};
    print "'$name' is '$p->{name}'\n";
    

    This is what I'd use if I don't need to assign to $name.

    If you want to be able to write through $name, the easiest way is to make it a reference:

    use strict;
    use warnings;
    my $p = { name => "Joe" };
    my $name = \$p->{name};
    print "'$$name' is '$p->{name}'\n";
    $$name = "Jill";
    print "'$$name' is '$p->{name}'\n";
    

    If you really want an alias, the easiest way is to abuse a for loop:

    use strict;
    use warnings;
    my $p = { name => "Joe" };
    for my $name ($p->{name}) {
        print "'$name' is '$p->{name}'\n";
        $name = "Jill";
        print "'$name' is '$p->{name}'\n";
    }
    

    If your perl is new enough (5.22+), you can also do aliasing through references:

    use strict;
    use warnings;
    use feature 'refaliasing';
    my $p = { name => "Joe" };
    \my $name = \$p->{name};
    print "'$name' is '$p->{name}'\n";
    $name = "Jill";
    print "'$name' is '$p->{name}'\n";
    

    Finally, you can do aliasing to package variables by assigning to typeglobs, but that's not something I'd actually use here:

    use strict;
    use warnings;
    my $p = { name => "Joe" };
    *name = \$p->{name};  # sets *name{SCALAR} to point to $p->{name}
    our $name;            # declares $name so we can use it to refer to $main::name
    print "'$name' is '$p->{name}'\n";
    $name = "Jill";
    print "'$name' is '$p->{name}'\n";