Perl references

From "A B C"
Jump to navigation Jump to search

Perl references


The contents of this page has recently been imported from an older version of this Wiki. This page may contain outdated information, information that is irrelevant for this Wiki, information that needs to be differently structured, outdated syntax, and/or broken links. Use with caution!


Passing objects by reference, and dereferencing for access.



In Perl, when you assign a multi-dimensional object (such as an array, or a hash) to another, the object is copied. This is usually the desired behaviour, but not always, especially when you are creating or modifying the object in a subroutine and then need to work with it in the main body of the program. Since datastructures can be quite large, copying them in the process of returning them from a subroutine can be quite inefficient. There are two ways to get around this, depending on the specific situation, both are in common use.

1 - use a global variable
The scope of a variable that is defined in the main body of the program is for the entire code, including all subroutines. You can thus define a variable outside of the routine and then use it inside; you do not necessarily have to pass it into the routine as an argument. This is easy and straightforward, but it invites side-effects and it makes the subroutines impossible to reuse in a modular way. Here is an example:
#!/usr/bin/perl -w

my $Global = 'U';
transmogrify();
print "$Global\n";

exit;

sub transmogrify {
   $Global = 'X';
return;
}


2 - Pass the object by reference
instead of returning the entire object as the result, you only return the location of that object in memory, a reference to the object, as the return value. The object then does not need to be copied. This is elegant, because it keeps the inner workings of the routine isolated from the rest of the program, but there is a bit of programming overhead, because in order to actually use the object, you need to dereference it.

Here is an example that shows how references are created and derefrenced:

#!/usr/bin/perl -w
# a small exercise in syntax for passing by value and by reference
use strict;

# a reference to an object is created by prepending a backslash:
my $value = "A string.";
my $r_val = \$value;

print "1: ", $value, "\n";
print "2: ", $r_val, "\n";

# dereferencing is achieved by prepending a sigil for the appropriate type
# ($, @ or %) to the reference
print "3: ", $$r_val, "\n";

# same with arrays
my @array = ('A', 'B', 'C');
my $r_arr  = \@array;
print "4: ", $r_arr, "\n";

foreach my $element (@array) {
        print "  5: ", $element, "\n";
}

foreach my $element (@$r_arr) {
        print "  6: ", $element, "\n";
}

print "7: ", $array[1], "\n";
print "8: ", $$r_arr[1], "\n";

# same with hashes
my %hash = ('A' => 0, 'B' => 1, 'C' => 2);
my $r_hsh  = \%hash;
print "9: ", $r_hsh, "\n";

# note that the order you get out is not necessarily the order you have put in
foreach my $key (keys(%hash)) {
        print "  10: ", $key, " - ", $hash{$key},"\n";
}

foreach my $key (keys(%$r_hsh)) {
        print "  11: ", $key, " - ", $$r_hsh{$key},"\n";
}


exit;

And here is an example how this is used in the context of subroutines:

#!/usr/bin/perl -w
# a small exercise in syntax for passing by value and by reference
# version two - using subroutines
use strict;

# this time we create objects in a subroutine, then return the
# object reference as a return value

my $r_val = scalar_ref();
print "1: ", $r_val, "\n";
print "2: ", $$r_val, "\n";

# same with arrays
my $r_arr  = array_ref();
print "3: ", $r_arr, "\n";

foreach my $element (@$r_arr) {
        print "  4: ", $element, "\n";
}
print "5: ", $$r_arr[1], "\n";

# same with hashes
my $r_hsh  = hash_ref();
print "6: ", $r_hsh, "\n";

foreach my $key (keys(%$r_hsh)) {
        print "  7: ", $key, " - ", $$r_hsh{$key},"\n";
}

exit;

sub scalar_ref {
        my $s = "A string.";
        return(\$s);
}

sub array_ref {
        my @a = ('A', 'B', 'C');
        return(\@a);
}

sub hash_ref {
my %h = ('A' => 0, 'B' => 1, 'C' => 2);
        return(\%h);
}



   

Further reading and resources