#!/usr/bin/perl

# Okay. I got really tired on never really understanding dereferencing in
# Perl. It's like having a brand new socket set in the tool box but you
# can't use it because you don't know how to get the open the case. I have
# done what I considered cheap-ass work-arounds in the past because of a
# lack of understanding. So I decided it was time to invest the two hours
# into it and once and for all figure this thing out. 
# 
# As I did it I made a crib sheet. Attached is that sheet. I did not do
# refs of refs to arrays of array refs, but change {key} to [0] in the
# last example and you have it. If someone is collecting this sort of
# thing on a web page miniathens would be a good choice for future
# reference (get it? "reference").

# My it lead you to reference heaven
# Mike Stute

# It's the damn syntax that will kill you
use strict;

# Deferencing Demystified (yeah right)

my @ary=("This","is","an","array");
my %hash=( language=>'Perl refs',
	   action=>'make',
	   possesive=>'heads',
	   verb=>'hurt');
my %other=(another=>'hash',
	   hash=>'definition');

# An array of hash refs
my @recs;
$recs[0]=\%hash;
$recs[1]=\%other;

my $aryref=\@ary;
my $hashref=\%hash;

# And Mr Nasty - a reference to an array of hash references
my $refref=\@recs;

#Many ways to dereference
print "Element 0 of \@ary is $$aryref[0] Better: $aryref->[0]\n";
print "Last of element of  \@ary is $#{$aryref} \n";

#Now hashes
print "Entry 'action' of \%hash is $$hashref{action} Better:$hashref->{action}\n";

foreach my $key (keys %hash) {
    print "Key $key\n";
}
print "------------------------------\n";

foreach my $val (values %hash) {
    print "Val $val\n";
}
print "------------------------------\n";

foreach my $key (keys %hash) {
    print "Key $key = $hash{$key}\n";
}
print "------------------------------\n";

print "Number of keys/total entries in \%hash = " . %hash ."\n";
print "------------------------------\n";

# Now with the reference
foreach my $key (keys %{$hashref}) {
    print "Key $key\n";    
}
print "------------------------------\n";

foreach my $val (values %{$hashref}) {
    print "val $val\n";
}
print "------------------------------\n";

foreach my $key (keys %{$hashref}) {
    print "Key $key = $hashref->{$key}\n";
}
print "------------------------------\n";
print "Number of keys/total entries in \$hashref = " . %{$hashref} ."\n";

# Now arrays of hashes
print "------------------------------\n";
print "Last entry in \@recs is $#recs\n";

# Print out the keys
print "------------------------------\n";
print "Recs[0] action = $recs[0]->{'action'}\n";
print "Recs[1] hash = $recs[1]->{'hash'}\n";

print "------------------------------\n";
# Go through them
foreach my $ref (@recs) {
    foreach my $key (keys %{$ref}) {
	print "key $key = $ref->{$key}\n";
    }
}

print "------------------------------\n";
# Maybe recs is big and you don't have enough memory for the foreach
for(my $i=0;$i<$#recs+1;$i++) {
    foreach my $key (keys %{$recs[$i]}) {
	print "Key $key = $recs[$i]->{$key}\n";
    }
}

print "------------------------------\n";
# Maybe recs is big and maybe the hash it contains is big too
# foreach is memory hungry since the second arg expands to the whole list all at one
# This method is very memory efficient
for(my $i=0;$i<$#recs+1;$i++) {
   while ( my($key, $value) = each %{$recs[$i]}) {
     print "Key $key = $value\n";
   }  
}
print "------------------------------\n";

# And now the mother of all ref storms the ref to an array of refs to hash
# Something I want to return from functions all the time

# With foreach
foreach my $href (@{$refref}) {
    foreach my $key (keys %{$refref->[0]}) {
	print "Key = $key = $$refref[0]->{$key} Better: Key = $key = $refref->[0]->{$key}\n";
    }
}
print "------------------------------\n";
# With whiles
for(my $i=0;$i<$#{$refref}+1;$i++) {
   while ( my($key, $value) = each %{$refref->[$i]}) {
     print "Key $key = $value\n";
   }  
}

print "------------------------------\n";
print "Last entry in in recs: $#{$refref}\n";
print "Number of keys/total entries in \$refref hash 1 = " . %{$refref->[0]} ."\n";


# Now don't I look smart.