Learning Perl - References


Learning Perl - References


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;
Enter fullscreen mode Exit fullscreen mode

To dereference a scalar reference, you use the dereferencing operator ('$'). For example:

my $value = $$scalar_ref;  # This will give you the value 42
Enter fullscreen mode Exit fullscreen mode

To change the value of the scalar through the reference, you can do:

$$scalar_ref = 100;  # Now $scalar is 100
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

To dereference a hash reference, you use the '%' operator:

my %values = %$hash_ref;  # This will give you (a => 1, b => 2)
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

or you can add a new key-value pair:

$hash_ref->{e} = 5;  # Now %hash is (c => 3, d => 4, e => 5)
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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
        }
    ];
Enter fullscreen mode Exit fullscreen mode

Now let's see what happens when we change the original hash:

$hash{name} = 'Dave';
print Dumper(\@array_of_hashes);
Enter fullscreen mode Exit fullscreen mode

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
        }
    ];
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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
    };
Enter fullscreen mode Exit fullscreen mode

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 }
);
Enter fullscreen mode Exit fullscreen mode

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.

Related Blogs

Learning Perl – Introduction
Perl has long been known as the “duct tape of the Internet,” or "the Swiss Army chainsaw of scripting...
Learning Perl - Variables
I will attempt to explain things in this post in a way that is easy to understand, even for those who...
Learning Perl - Arrays
As stated in the previous post, Perl has three types of variables: scalars, arrays and hashes. Today...
Learning Perl - Hashes
In the last post we covered the basics of arrays, today we will look at hashes in more detail. What...
Learning Perl - Conditional Statements
So far we have covered basic variables in Perl, today we are going to look at how to use these...
Learning Perl - Loops and Iteration
In previous posts, we explored variables, arrays, hashes, and conditional statements in Perl. Now...
Learning Perl - Scalars
Before moving onto more complex topics lets come back to how we represent data in Perl. The most...
Learning Perl - Ternary Operators
In a previous post, we learned about conditional statements in Perl. The ternary operator is an...
Learning Perl - Subroutines
Subroutines are one of the most important building blocks in programming. They allow you to organise...
Learning Perl - Regular Expressions
Regular expressions also known as regex or regexp, are a powerful way to match patterns in text. Most...
Learning Perl - Modules
A module in Perl is a reusable piece of code that can be included in your scripts to provide...
Learning Perl - CPAN
In the last post I showed you how to create a new module and how to use it in your code. In this post...
Learning Perl - Plain Old Documentation
When you write and program in any language it is good practice to document your code. Each language...
Learning Perl - Testing
In this post we will look at how to test Perl code using the Test::More module. Like documentation,...
Learning Perl - Exporting
In programming, we often want to share functionality across different parts of our code. In Perl,...
Learning Perl - Object Orientation
Object-Oriented Programming (OOP) is a widely used programming paradigm that enables the creation of...
Learning Perl - Inheritance
In the last post we discussed Object Oriented Programming in Perl, focusing on the basics of creating...
Learning Perl - File Handles
In programming file processing is a key skill to master. Files are essential for storing data,...
Learning Perl - Prototypes
Today we are going to discuss Perl subroutine prototypes, which are a way to enforce a certain...
Learning Perl - Overloading Operators
In the last post we investigated prototype subroutines in Perl. In this post, we will look at...