Search code examples
perlaliassubroutinelexical-scope

Returning an alias from a subroutine in Perl


Is it possible to return an alias from a subroutine in Perl?

I have a simple example:

#!/usr/bin/perl
use warnings;
use strict;
use feature qw{ say };

{
    package Test;
    my $value = 'old';

    sub get_value {
        return \$value;
    }

    sub set_value {
        my ($x) = @_;
        $value = $x;
    }
}

my $test = Test::get_value();
say $$test;

Test::set_value('new');
say $$test;

This is essentially the functionality I want, however I would like to find a way to make $test and alias to $value so I can access the data without dereferencing it. Is this possible?


Here is an example of the syntax I want:

ex (pseudo code):

#!/usr/bin/perl
use warnings;
use strict;
use feature qw{ say };

{
    package Test;
    my $value = 'old';

    sub get_value {
        # return alias to $value
    }

    sub set_value {
        my ($x) = @_;
        $value = $x;
    }
}

# Gets an alias, NOT a reference
my $test = Test::get_value();

# Print old
say $test;

Test::set_value('new');

# Print new
say $test;

I've been reading about aliases and everything keeps pointing to "typeglobs"... but it looks like using typeglobs requires the use of global variables and I would really like to avoid that.


Also I would like a solution that doesn't require installing any additional modules from CPAN since I need to get them approved by security and have them install it ... and so would anyone else here who wants to use my script.


Solution

  • First a word of warning. You are requesting information on performing an extremely poor practice. Actions at a distance should be eliminated, not sought.


    You can bind two names to the same SV. A name bound as such is called an alias. You can't return a bound name, so you can't return an alias.

    How about returning an object that overloads stringification?

    $ perl -E'
       use String::Defer qw( );
    
       {
          my $value = "old";
          sub set_value { $value = $_[0] }
          sub get_value { String::Defer->new(\$value) }
       }
    
       {
          my $value = get_value();
          say $value;
          set_value('new');
          say $value;
       }
    '
    old
    new
    

    What you should do instead is return a reference.

    $ perl -E'
       {
          my $value = "old";
          sub set_value { $value = $_[0] }
          sub get_ref { \$value }
       }
    
       {
          my $value_ref = get_ref();
          say $$value_ref;
          set_value('new');
          say $$value_ref;
       }
    '
    old
    new