Perl references
Perl references
Passing objects by reference, and dereferencing for access.
Contents
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