#!/usr/bin/perl
use warnings;
use diagnostics;
use strict; # disallow symbolic references but allow hard references

# references.pl
#
# Please send corrections, suggestions for improvement, comments etc. to
# chandra@ee.uwa.edu.au
# 
# This program illustrates the various types of standard references in Perl
# and how to identify and print them out.

my ($answer, $answer_sref, $answer_sref_ref, $handle_gref, $glob_gref);
my (@numbers, $numbers_aref);
my (%capitals, $capitals_href);
my ($print_all_cref);

$answer = 42; # courtesy of Douglas Adams
@numbers = (0, 1, "pi", "i", "e"); # mixture of numbers and quoted literals
# Ensure that there is an even number of elements in the hash
# especially when written like this
%capitals = qw(UK London France Paris Australia Canberra Iceland Reykjavik);

$answer_sref = \$answer; # reference to a scalar
$answer_sref_ref = \$answer_sref; # reference to another reference
$numbers_aref = \@numbers; # reference to an array
$capitals_href = \%capitals; # reference to a hash
$print_all_cref = \&print_all; # reference to a subroutine/code
$handle_gref = \*STDOUT; # reference to a filehandle

# Invoke subroutine with different types of references
# including numbers and quoted literals
print_all($capitals_href, $numbers_aref, $answer_sref,
$answer_sref_ref, $print_all_cref, $handle_gref, 1.414, "home alone");

sub print_all
    {
    my $count = 0;
    my ($ref, $key, $value); # do not forget parentheses!
    while ($ref = shift)
        {
        $count++;
        if (ref($ref) =~ m/HASH/)
            {
            print "arg $count hash reference --> $ref\n";
            while (($key, $value) = each %$ref)
                {
                print "arg $count hash key-value pair --> ",
                    "$key => $value\n";
                }
            }
        elsif (ref($ref) =~ m/ARRAY/)
            {
            print "arg $count array reference --> $ref\n";
            print "arg $count array value(s) -->  @$ref\n";
            }
        elsif (ref($ref) =~ m/SCALAR/)
            {
            print "arg $count scalar reference --> $ref\n";
            print "arg $count scalar value --> $$ref\n";
            }
        elsif (ref($ref) =~ m/REF/)
            {
            print "arg $count reference reference --> $ref\n";
            print "arg $count reference value --> $$ref\n";
            }
        elsif (ref($ref) =~ m/CODE/)
            {
            print "arg $count subroutine reference --> $ref\n";
            print "arg $count subroutine value --> &$ref\n";
            }
        elsif (ref($ref) =~ m/GLOB/)
            {
            print "arg $count glob reference --> $ref\n";
            print "arg $count glob value --> &$ref\n";
            }
        else
            {
            print "Sorry, arg $count, I do not think you are a reference.\n";
            print "arg $count value --> $ref\n";
            }
        }
    }