Beefy Boxes and Bandwidth Generously Provided by pair Networks chromatic writing perl on a camel
Problems? Is your data what you think it is?
 
PerlMonks  

Comment on

( #3333=superdoc: print w/ replies, xml ) Need Help??

References

This is a translation of (lang: de) Referenzen

(ASCII Graphics in style of PEGS (PErl Graphical Structures) by Joseph Hall)

What is a reference?

There are two kinds of references 'hard references' and 'soft references'. The 'soft' ones are sometimes called 'symbolic' and are not part of this tutorial.

A reference is something like a pointer to a value (I know there are no pointers in Perl like there are in C):

+-----------+ +-----------+ | O-----+----->| 12345 | +-----------+ +-----------+

References are often stored in variables:
+----------\ +----------\ | a > | b > +----------/ +----------/ | | +-----------+ +-----------+ | O-----+----->| 12345 | +-----------+ +-----------+

The variable $a contains a reference pointing to the value of variable $b.


References are not restricted to pointing to values, they can also point to arrays and hashes. Here some examples:
+----------\ | b > +----------\ +----------/ | a > | +----------/ +-----------+ | | O-----+----->+###########+ +-----------+ +"""""""""""+ | Foo | +----------\ +-----------+ | c > | Bar | +----------/ +-----------+ | | Baz | +-----------+ +-----------+ | O-----+----->| Qux | +-----------+ +-----------+

Reference $b points to array @a, reference $c points to the fourth element of @a, $a[3].

This way you can construct datastructures of arbitrary complexity:
+----------\ | a > +-->+###########+ +----------/ | +"""""""""""+ | | | Foo | +-----------+ | +-----------+ | O-----+----->+###########+ | | Bar | +-----------+ +"""""""""""+ | +-----------+ | O-----+---+ +-----------+ | O-----+------>+###########+ +-----------+ +"""""""""""+ | O-----+---+ | Baz | +-----------+ | +-----------+ | | Qux | | +-----------+ | | +-->+###########+ +"""""""""""+ | Baz | +-----------+
A reference to a list containing references to several lists.


+----------\ | a > +-->+###########+ +----------/ | +"""""""""""+ | | | Foo | +#########################+ | +-----------+ +"""""""""""""""""""""""""+ | | Bar | +-----------\ +-----------+ | +-----------+ | aaa >| O-----+---+ +-----------< +-----------+ | bbb >| O-----+------>+###########+ +-----------< +-----------+ +"""""""""""+ | ccc >| O-----+---+ | Baz | +-----------/ +-----------+ | +-----------+ | | Qux | | +-----------+ | | +-->+###########+ +"""""""""""+ | Baz | +-----------+
A hash containing references to lists.


How to create references?

The backslash operator creates a reference to a value:

$cref = \12345 Reference to a constant
$sref = \$s Reference to the value of $s
$aref = \@a Reference to the array @a
$href = \%h Reference to the hash %h
$fref = \&f Reference to the subroutine &f

A reference to an anonymous array is created like this:
$aref = [123, 456, 789];
A reference to an anonymous hash:
$href = {NAME => 'Bernd', EMAIL => 'bdulfer@sybase.com'};
A reference to an anonymous subroutine:
$fref = sub { print "AnonSub\n" };

What are references good for?

Case 1, arguments of subroutines:
When several arrays are given to a subroutine, Perl creates one list of values named @_. There is no possibility to determine which elements are from which array. If you need these informations, you can pass references to the arrays. The references can then be dereferenced via @_ and the values can be related to the arrays.

(useless :-) example:

use Data::Dumper; sub make_hash_from_arrays { my ($aref1, $aref2) = @_; my %hash; $hash{$_} = shift @$aref2 foreach (@$aref1); print Dumper(\%hash); } my @a = ('a', 'b', 'c', 'd'); my @b = (1, 2, 3, 4); make_hash_from_arrays(\@a, \@b);
The meaning of @$ is explained later.

Case 2. complex datastructures:
A datastructure containing an addressbook.
Without references there are the following possibilities:

1. The addresses are put into a hash, the values of each address are separated by a delimiter. To get distinct values, split is used:

$address{Bernd} = 'Bernd Dulfer|Kapellenstr. 1|bdulfer@sybase.com' +; $email = (split(/\|/, $address{bernd}))[2];
2. The address is distributed over several hashes. To display an address elements are fetched from those hashes:
$name{Bernd} = 'Bernd Dulfer'; $str{Bernd} = 'Kapellenstr. 1'; $email{Bernd} = 'bdulfer@sybase.com'; print_address($name{Bernd}, $str{Bernd});

Both methods are inelegant and unwieldy. Here the solution with references:
A hash containing references to the addresses, each address is a hash on its own.
+----------\ | address > +----------/ | +#######################+ +"""""""""""""""""""""""+ +-----------\ +---------+ | Bernd >| O----+----->+##################################+ +-----------/ +---------+ +""""""""""""""""""""""""""""""""""+ +-----------\ +--------------------+ | Name >| Bernd Dulfer | +-----------< +--------------------+ | Str >| Kapellenstr. 1 | +-----------< +--------------------+ | EMail >| bdulfer@sybase.com| +-----------/ +--------------------+ $address{Bernd} = { Name => 'Bernd Dulfer', Str => 'Kapellenstr. 1', EMail => 'bdulfer@sybase.com' }; $email = $address{Bernd}->{EMail}; print_address($address{Bernd});
You want to store in addition to the addresse, for instance, a list of lended books. It is almost impossible to do this without references, with references it's like this:
+----------\ | address > +----------/ | +##########+ +""""""""""+ +----\ +---+ |Bernd>| O-+->+###########################+ +----/ +---+ +"""""""""""""""""""""""""""+ +------\ +------------------+ |Name >|Bernd Dulfer | +------< +------------------+ |Str >|Kapellenstr. 1 | +------< +------------------+ |EMail >|bdulfer@sybase.com| +------< +------------------+ |Books >| O---------+->+#####################+ +------/ +------------------+ +"""""""""""""""""""""+ |Lord of the Rings | +---------------------+ |Hitchhikers Guide ...| +---------------------+ |The Color of Magic | +---------------------+ $address{Bernd} = { Name => 'Bernd Dulfer', Str => 'Kapellenstr. 1', EMail => 'bdulfer@sybase.com', Books => [ 'Lord of the Rings', 'Hitchhikers Guide to the Galaxy', 'The Color of Magic' ] };

How do I use references and datastructures?

References are dereferenced by using the sigil ($%@&) of the value and { }.
When the reference is stored in a variable, the curlies can be omitted.
Examples:

A reference to a scalar:
$s = 'qwertz'; $sref = \$s; print ${$sref}, "\n"; print $$sref, "\n";
Prints:
qwertz qwertz

A reference to an array:
$, = ':'; @a = (123, 456, 789); $aref = \@a; print @{$aref}, "\n"; print @$aref, "\n";
Prints:
123:456:789 123:456:789

To get single elements, use
${$aref}[1] or $$aref[1]

When references are stored in an array or hash, use ->:
$address{Bernd} = { Name => 'Bernd Dulfer', Str => 'Kapellenstr. 1', EMail => 'bdulfer@sybase.com', Books => [ 'Lord of the Rings', 'Hitchhikers Guide to the Galaxy', 'The Color of Magic' ] }; print 'Name: ', $address{Bernd}->{Name}, "\n";
Prints:
Name: Bernd Dulfer

In the same way assingments are handled:
$address{Bernd}->{Books}->[3] = 'Goedel, Escher, Bach - An Eternal + Golden Braid';
The reference in $address{Bernd} is dereferenced and gives a hash. From this hash the value with the key 'Books', which is a reference, is used. This reference is again dereferenced and gives a list, of which the fourth element gets a new value.


If something dereferenced shall be used not as a scalar but as an array, it has to be dereferenced with the sigil and { }:

push @{$address{Bernd}->{Books}}, 'Icerigger';
$address{Bernd} contains a reference to an anonymous hash, which can be accessed by using ->.
$address{Bernd}->{Books} contains a reference to an anonymous array.
To use this array, the reference must be dereferenced with @{ }.

This was perhaps a bit fast, therefor here some examples:

A list of authors and books will be added to the address.
The authors are stored in a hash. The keys are the names of the authors, the values are references to lists of booktitles. To create the hash of authors separately, use:

%authors = ( Tolkien => [ 'The Silmarillion', 'Unfinished Tales' ], Pratchett => [; 'Guards! Guards!', 'Feet of Clay' ] )
A reference to this hash can be added to the address:
$address{Bernd}->{Authors} = \%authors;
A new book by Tolkien is added using:
push @{$authors{Tolkien}}, 'The Hobbit';


How can I look into complex datastructures?

The module Data::Dumper has a function Dumper. Pass a reference to this function and Dumper creates Perlcode, representing the whole structure:

#!/usr/bin/perl use strict; use warnings; use Data::Dumper; my %address; $address{Bernd} = { Name => 'Bernd Dulfer', Str => 'Kapellenstr. 1', EMail => 'bdulfer@sybase.com', Books => [ 'Lord of the Rings', 'Hitchhikers Guide to the Galaxy', 'The Color of Magic' ] }; $address{Bernd}->{Books}->[3] = 'Goedel, Escher, Bach - An Eternal + Golden Braid'; push @{$address{Bernd}->{Books}}, 'Icerigger'; $address{Bernd}->{Authors}->{Tolkien} = ['Silmarillion', 'Unfinish +ed Tales']; print Dumper(\%address);
Take a close look at the line containing ['Silmarillion', 'Unfinished Tales'].
A new hash element with the key 'Authors' is created 'on the fly'. The value is a reference to an anonymous hash with the element 'Tolkien'.
The value of this element is an anonymous array.

The output:
$VAR1 = { 'Bernd' => { 'Authors' => { 'Tolkien' => [ 'Silmarillion', 'Unfinished Tales +' ] }, 'Books' => [ 'Lord of the Rings', 'Hitchhikers Guide to the Galaxy', 'The Color of Magic' 'G&ouml;del, Escher, Bach - An Ete +rnal Golden Braid', 'Icerigger' ], 'EMail' => 'bdulfer@sybase.com', 'Str' => 'Kapellenstr. 1', 'Name' => 'Bernd Dulfer' } };
You get a similar display when you use the Tk-debugger (Devel::ptkdb).

How can I load data from a file into a complex datastructure?

Consider the following file:

#Short Name Str EMail Books Bernd |Bernd Dulfer |Kapellenstr. 1 |bdulfer@sybase.com |(Lord of + the Rings|Hitchhikers Guide ...|The Color of Magic) Bilbo |Bilbo Baggins |Bagend | |(The Red + Book)
The following code creates the well known hash:
1: my %addresses; 2: 3: open ADDRESSES, 'addresses.dat' or die "Cannot open addresses.d +at: $!\n"; 4: while (<ADDRESSES>) { 5: next if /^#/; 6: my ($short, $name, $str, $email, $books) = split(/\s*\|/, $_, + 5); 7: $addresses{$short} = { 8: Name => $name, 9: Str => $str, 10: EMail => $email 11: }; 12: $books =~ tr/()//d; 13: push @{$addresses{$short}->{Books}}, split /\|/, $books; 14: } 15: close ADDRESSES;
Line 1: declare the hash %addresses.
Line 3: Open file addresses.dat for reading.
Line 4: Read each line. Each line is put into $_ automagically.
Line 5: Ignore comments.
Line 6: Split line into five values which are assigned to variables.
Line 7: An anonymous hash with the keys 'Name', 'Str' and 'EMail' is created and a reference to this is stored in the hash %addresses with the key $short.
Line 12: The parens are removed from the list of books.
Line 13: The books are splitted by '|' and put into an anonymous array. A reference to this is stored in the hash %addresses.
Line 15: The file is closed.

This is only an example, several things remain unconsidered. For instances a booktitle may contain parens.

How can I iterate through arrays and hashes in datastructures?

All books of a given address:

foreach (@{$address{Bernd}->{Books}}) { print $_, "\n"; }
All authors with their books:
foreach (keys %{$address{Bernd}->{Authors}}) { print $_, "\n"; foreach (@{$address{Bernd}->{Authors}->{$_}}) { print "\t", $_, "\n"; } }

What are references to subroutines good for?

References to subroutines are used for several things:

Callbacks:
    In a module a subroutine of the main program shall be executed without the module knowing the name of that subroutine.
    A reference to the subroutine is passed to the module.:

Package Mod; my $callback; sub set_callback { $callback = shift; } sub do_something { do_this(); do_that(); &$callback; do_something_else(); } . . . 1; __END__ #!/usr/bin/perl use strict; use warnings; use Mod; Mod::set_callback(\&print_rubbish); Mod::do_something(); sub print_rubbish ( print "Rubbish!\n"; }
Tk programmer often use callbacks, events (mouse click, button, ...) are passed to and processed by callbacks.

Dispatch Lists:
   To avoid large if/elsif/else constructs, pieces of code are put into subroutines.
   References to these subroutines are stored in a hash.The keys represent the conditions.

%dispatch = ( insert => \&insert, update => \&update, delete => \&delete ) $dispatch{$token}->($query);


Update: wrong brackets in two places, caught by petral
Update: replaced (PEGS) link


In reply to intro to references by busunsl

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • Outside of code tags, you may need to use entities for some characters:
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.
  • Log In?
    Username:
    Password:

    What's my password?
    Create A New User
    Chatterbox?
    and the web crawler heard nothing...

    How do I use this? | Other CB clients
    Other Users?
    Others surveying the Monastery: (7)
    As of 2014-04-17 08:56 GMT
    Sections?
    Information?
    Find Nodes?
    Leftovers?
      Voting Booth?

      April first is:







      Results (441 votes), past polls