In the last post we learnt how to create a reference to a scalar, an array, and a hash. In this post, we will learn how to dereference these references and some of the caveats that perl has when it comes to dealing with references.
Firstly in Perl it's important to understand that references are scalar values. This means that you can create a reference to a reference, and a reference to a reference to a reference, and so on. This is called a "deep reference" in programming.
To declare a reference to any scalar, you use the backslash operator ('\'). For example:
my $scalar = 42;
my $scalar_ref = \$scalar;
To dereference a scalar reference, you use the dereferencing operator ('$'). For example:
my $value = $$scalar_ref; # This will give you the value 42
To change the value of the scalar through the reference, you can do:
$$scalar_ref = 100; # Now $scalar is 100
To create a reference to an already instantiated array then we can also use the '\' character, however you can also instantiate array references with the '[]' chracters instead of '()' when declaring.'
my $array_ref = [1, 2, 3];
# ... or
my @array = (1, 2, 3);
my $array_ref = \@array;
To dereference an array reference, you use the '@' operator:
my @values = @$array_ref; # This will give you (1, 2, 3)
To change the values of the array through the reference, you can do:
@$array_ref = (4, 5, 6); # Now @array is (4, 5, 6)
Hashes work the same as arrays in the sense to create a reference to an already instantiated hash you just use '\'. However to create a hash reference you can use the '{}' characters instead of the '()' characters when declaring.
my $hash_ref = { a => 1, b => 2 };
# ... or
my %hash = (a => 1, b => 2);
my $hash_ref = \%hash;
To dereference a hash reference, you use the '%' operator:
my %values = %$hash_ref; # This will give you (a => 1, b => 2)
To change the values of the hash through the reference, you can do:
%$hash_ref = (c => 3, d => 4); # Now %hash is (c => 3, d => 4)
or you can add a new key-value pair:
$hash_ref->{e} = 5; # Now %hash is (c => 3, d => 4, e => 5)
To create a deep reference, you can create a reference to a reference. For example:
my $deep_scalar_ref = \$scalar_ref; # Reference to a scalar reference
my $deep_array_ref = \$array_ref; # Reference to an array reference
my $deep_hash_ref = \$hash_ref; # Reference to a hash reference
You will not do this often in my experience, but it is useful to know that you can do this.
Today our example is going to be using an array of hashes, which is a common data structure in Perl. I am going to highlight some behaviour that you may not expect but is important to understand. We are going to declare one of our hashes as a hash and then create a reference to it within our array of hashes. Create a new file 'references.pl' and add the following code:
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
my %hash = (name => 'Alice', age => 30);
my @array_of_hashes = (
\%hash,
{ name => 'Bob', age => 25 },
{ name => 'Charlie', age => 35 }
);
print Dumper(\@array_of_hashes);
Nothing unusual about this code, we are just creating a hash and then creating an array of hashes that contains a reference to the hash we created plus a few extra hash references that we define inline.
Now when you run the script you will see the following output:
$VAR1 = [
{
'name' => 'Alice',
'age' => 30
},
{
'name' => 'Bob',
'age' => 25
},
{
'name' => 'Charlie',
'age' => 35
}
];
Now let's see what happens when we change the original hash:
$hash{name} = 'Dave';
print Dumper(\@array_of_hashes);
When you run the script again after changing the original hash, you will see the following output:
$VAR1 = [
{
'name' => 'Dave',
'age' => 30
},
{
'name' => 'Bob',
'age' => 25
},
{
'name' => 'Charlie',
'age' => 35
}
];
We have changed the value in the hash and it has updated the value in the array of hashes as well. This is because the array of hashes contains a reference to the original hash, so any changes made to the original hash will be reflected in the array of hashes.
You can also do this the other way around so update the value in the array of hashes and it will update the original hash as well. For example:
$array_of_hashes[0]{name} = 'Eve';
print Dumper(\@array_of_hashes);
print Dumper(\%hash);
When you run the script again after changing the value in the array of hashes, you will see the following output:
$VAR1 = [
{
'name' => 'Eve',
'age' => 30
},
{
'name' => 'Bob',
'age' => 25
},
{
'name' => 'Charlie',
'age' => 35
}
];
$VAR1 = {
'name' => 'Eve',
'age' => 30
};
This behaviour can be useful, but can also lead to unexpected results if you are not careful. A way to avoid this is to create a copy of the hash when you create the reference, to test you can update the array_of_hashes to contain a copy of the hash by using {%hash}
instead of a reference to the original '\':
@array_of_hashes = (
{%hash},
{ name => 'Bob', age => 25 },
{ name => 'Charlie', age => 35 }
);
Now when you run the script again after changing the original hash, you will see that the value in the array of hashes does not change.
It's important to understand that references in Perl are powerful tools that allow you to create complex data structures and manipulate them efficiently. However, they can also lead to confusion if you are not careful about how you use them. In the next post we will explore more concise way of performing conditional statements by using the ternary operator, which is a shorthand for an if-else statement. This will help you write cleaner and more readable code when dealing with simple conditional logic.
Top comments (0)