Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight

intro to references

by busunsl (Vicar)
on Jan 08, 2002 at 16:38 UTC ( #137108=perltutorial: print w/replies, xml ) Need Help??


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 => ''};
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|' +; $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} = ''; 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 >|| +-----------/ +--------------------+ $address{Bernd} = { Name => 'Bernd Dulfer', Str => 'Kapellenstr. 1', EMail => '' }; $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 >|| +------< +------------------+ |Books >| O---------+->+#####################+ +------/ +------------------+ +"""""""""""""""""""""+ |Lord of the Rings | +---------------------+ |Hitchhikers Guide ...| +---------------------+ |The Color of Magic | +---------------------+ $address{Bernd} = { Name => 'Bernd Dulfer', Str => 'Kapellenstr. 1', EMail => '', 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.

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

A reference to an array:
$, = ':'; @a = (123, 456, 789); $aref = \@a; print @{$aref}, "\n"; print @$aref, "\n";
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 => '', Books => [ 'Lord of the Rings', 'Hitchhikers Guide to the Galaxy', 'The Color of Magic' ] }; print 'Name: ', $address{Bernd}->{Name}, "\n";
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 => '', 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' => '', '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 | |(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:

    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

Replies are listed 'Best First'.
Re: references
by Juerd (Abbot) on Jan 08, 2002 at 20:25 UTC
    You forgot to translate "qwertz" to "qwerty" ;)

    2;0 juerd@ouranos:~$ perl -e'undef christmas' Segmentation fault 2;139 juerd@ouranos:~$

Re: references
by planetscape (Chancellor) on Jul 01, 2005 at 04:36 UTC
Re: references
by nathanvit (Beadle) on Mar 22, 2003 at 18:06 UTC
    I'm a newbie of Perl and this lesson was very important for me! Thanks Perlmonks!!
Re: references
by Anonymous Monk on Jan 17, 2002 at 22:02 UTC
    Where you said,

    > Line 13: The books are splitted by '|' and put into an anonymous array. A reference to this is stored in the hash %addresses

    did you mean, "A reference to this is stored in the anonymous hash referenced at $short in the hash %addresses" ?

    (if so, were you trying to confuse us poor novices?;)

Re: references
by serah99 (Initiate) on Jun 10, 2005 at 18:17 UTC
    Yes, indeed, this is a really good artical and helps me a lot! I need to point out that in the example of reading from files, those fields for books should be assigned to a list (@books) instead of $book, becasuse you will lose the others if you do it that way and the last split didn't work since there was only one element left. thanks, serah99
Re: intro to references
by lowphive (Monk) on Feb 08, 2007 at 03:22 UTC
    yes! very good, and pictures. i'll never get too old for those.
Re: intro to references
by perl.j (Pilgrim) on Aug 03, 2011 at 03:14 UTC
    This is just what I needed to learn references! Thanks so much!
    perl.j-----A Newbie To Perl

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perltutorial [id://137108]
[Corion]: GrandFather: All's well that ends well? ;)
[GrandFather]: I'm fighting with a third party device our software is to support. The documentation for the device's SDK is quite a lot less than average and most of today was spent ...
[GrandFather]: discovering that one of the sensors for the device lies about the gain range it is using!
[GrandFather]: However, by the end of the day I had discovered its deceptions and now have it working correctly, so yes, all's well that ends well. :-D
[Corion]: GrandFather: Ah, (hardware) APIs - I have a similar situation with Chrome and its API... It is fairly underdocumented and I guess I have to hunt...
[Corion]: ... down supposedly working code to find out what I'm supposed to do
[GrandFather]: I haven't any "working code" to inspect! I have to find ways to generate reference signals then check the numbers I get at the far end match.
[GrandFather]: That's ok when the signal is a voltage, but there are three axis accelerometers, gyroscopes and magnetometers in these things! A little invention is needed at times!
[Corion]: GrandFather: Yeah, in that aspect, hardware is far more a black box than software

How do I use this? | Other CB clients
Other Users?
Others pondering the Monastery: (5)
As of 2017-08-24 07:08 GMT
Find Nodes?
    Voting Booth?
    Who is your favorite scientist and why?

    Results (365 votes). Check out past polls.