Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much
 
PerlMonks  

Tutorial RFC: Guide to Perl references, Part 1

by stevieb (Canon)
on Jul 07, 2015 at 20:45 UTC ( [id://1133627]=perlmeditation: print w/replies, xml ) Need Help??

NOTE: I've been considering translating this five part series I wrote a few years ago to PerlMonks, and I thought I'd go for it to see what others thought. Parts 2-5 are still linked to the blog to give context to the entire series. If people think this should be made into a Tutorial, I'll clean up and translate the rest of the docs and link them properly.

Thoughts?

BEGIN TUTORIAL...

Understanding references and their subtleties in Perl is one of the more difficult concepts to fully wrap one's head around. However, once they are fully understood by the blossoming developer, they find a whole new level of capability and power to exploit and explore.

I often see newer programmers struggle with the concept of references on the Perl help sites I frequent. Some still have a ways to go, but many are at the stage where perhaps one more tutorial may push them over the edge and give them that 'Ahhhh' moment of clarity. My moment of clarity came when I read Randal Schwartz's "Learning Perl Objects, References & Modules" book for the something like the 8th time. Although once the concept of references is understood, the syntax and use cases can still be confusing for quite some time, especially in Perl, because There Is More Than One Way To Do It.

This tutorial is the first in a five part series. This part will focus on the basics, preparing you for more complex uses in the following four parts. I've created a cheat sheet that summarizes what you'll learn in this document.

  • Part 1 - The basics (this document)
  • Part 2 - References as subroutine parameters
  • Part 3 - Nested data structures
  • Part 4 - Code references
  • Part 5 - Concepts put to use

I will stick with a single consistent syntax throughout the series and will refrain from using one-line shortcuts and other simplification techniques in loops and other structures in hopes to keep any confusion to a minimum. Part one assumes that you have a very good understanding of the Perl variable types, when they are needed, and how they are used. Some exposure to references may also prove helpful, but shouldn't be required.

THE BASICS

References in Perl are nothing more than a scalar variable that instead of containing a usable value, they 'point' to a different variable. When you perform an action on a reference, you are actually performing the action on the variable that the reference points to. A Perl reference is similar to a shortcut to a file or program on your computer. When you double click the shortcut, the shortcut doesn't open, it's the file that the shortcut points to that does.

We'll start with arrays, and I'll get right into the code.

We'll define an array as normal, and then print out its contents.

my @array = ( 1, 2, 3 ); for my $elem ( @array ){ say $elem; }

Prepending the array with a backslash is how we take a reference to the array and assign the reference to a scalar. The scalar $aref now is a reference that points to @array.

my $aref = \@array;

At this point, if you tried to print out the contents of $aref, you would get the location of the array being pointed to. You know you have a reference if you ever try to print a scalar and you get output like the following:

ARRAY(0x9bfa8c8)

Before we can use the array the reference points to, we must dereference the reference. To gain access to the array and use it as normal, we use the array dereference operator @{}. Put the array reference inside of the dereference braces and we can use the reference just as if it was the array itself:

for my $elem ( @{ $aref } ){ say $elem; }

The standard way of assigning an individual array element to a scalar:

my $x = $array[0];

To access individual elements of the array through the reference, we use a different dereference operator:

my $y = $aref->[1];

Assign a string to the second element of the array in traditional fashion:

$array[1] = "assigning to array element 2";

To do the same thing through an array reference, we dereference it the same way we did when we were taking an element from the array through the reference:

$aref->[1] = "assigning to array element 2";

You just learnt how take a reference to an array (by prepending the array with a backslash), how to dereference the entire array reference by inserting the reference within the dereference block @{}, and how to dereference individual elements of the array through the reference with the -> dereference operator. That is all there is to it. Hashes are extremely similar. Let's look at them now.

Create and initialize a normal hash, and iterate over its contents:

my %hash = ( a => 1, b => 2, c => 3 ); while ( my ( $key, $value ) = each %hash ){ say "key: $key, value: $value"; }

Take a reference to the hash, and assign it to a scalar variable:

my $href = \%hash;

Now we'll iterate over the hash through the reference. To access the hash, we must dereference it just like we did the array reference above. The dereference operator for a hash reference is %{}. Again, just wrap the reference within its dereferencing block:

while ( my ( $key, $value ) = each %{ $href } ){ say "key: $key, value: $value"; }

Access an individual hash value:

my $x = $hash{ a };

Access an individual hash value through the reference. The dereference operator for accessing individual elements of a hash through a reference is the same one we used for an array (->).

my $y = $href->{ a };

Assign a value to hash key 'a':

$hash{ a } = "assigning to hash key a";

Assign a value to hash key 'a' through the reference:

$href->{ a } = "assigning to hash key a";

That's essentially the basics of taking a reference to something, and then dereferencing the reference to access the data it points to.

When we operate on a reference, we are essentially operating on the item being pointed to directly. Here is an example that shows, in action, how operating directly on the item has the same effect as operating on the item through the reference.

my @b = ( 1, 2, 3 ); my $aref = \@b; # assign a new value to $b[0] through the reference $aref->[0] = 99; # print the array for my $elem ( @b ){ say $elem; }

Output:

99 2 3

As you can see, the following two lines are equivalent:

$b[0] = 99; $aref->[0] = 99;

CHEAT SHEET

Here's a little cheat sheet for review before we move on to the next part in the series.

my @a = ( 1, 2, 3 ); my %h = ( a => 1, b => 2, c => 3 ); # take a reference to the array my $aref = \@a; # take a reference to the hash my $href = \%h; # access the entire array through its reference my $elem_count = scalar @{ $aref }; # access the entire hash through its reference my $keys_count = keys %{ $href }; # get a single element through the array reference my $element = $a->[0]; # get a single value through the hash reference my $value = $h->{ a }; # assign to a single array element through its reference $a->[0] = 1; # assign a value to a single hash key through its ref $h->{ a } = 1;

This concludes Part 1 of our Guide to Perl references. My goal was not to compete with all the other reference guides available, but instead to complement them, with the hope that perhaps I may have said something in such a way that it helps further even one person's understanding. Next episode, we'll learn about using references as subroutine parameters.

Replies are listed 'Best First'.
Re: Tutorial RFC: Guide to Perl references, Part 1
by 1nickt (Canon) on Jul 08, 2015 at 04:00 UTC

    Hi stevieb, This is well done, a lot of work!

    I would consider shortening if possible; people have short attention spans sadly.

    Also I suggest using "anecdotal" var names in your tutorials, again, it holds attention better. Like this:

    # Very clear to a clear thinker my %hash = ( a => 1, b => 2, c => 3 ); while ( my ( $key, $value ) = each %hash ){ say "key: $key, value: $value"; }
    # More captivating to your average thinker my %rebels = ( Luke => 'Jedi', Han => 'human', Chewbacca => 'Wookie' ) +; while ( my ( $name, $species ) = each %rebel ){ say "Name: $name, Species: $species"; }

    Just my $0.02 :-)

    Remember: Ne dederis in spiritu molere illegitimi!
Re: Tutorial RFC: Guide to Perl references, Part 1
by afoken (Chancellor) on Jul 08, 2015 at 11:10 UTC

    NOTE: I've been considering translating this five part series I wrote a few years ago to PerlMonks, and I thought I'd go for it to see what others thought. Parts 2-5 are still linked to the blog to give context to the entire series. If people think this should be made into a Tutorial, I'll clean up and translate the rest of the docs and link them properly.

    Thoughts?

    What's wrong with perlref, perlreftut, perllol, perldsc, perldata? (And why don't you fix them?)

    Alexander

    --
    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)

      I don't know what's wrong with them, I haven't read them in a long time :)

      I wrote this tutorial just for fun years ago while I was playing around with perl6. I will take your comments into account and re-read the actual perldocs to see if I can put any effort into those.

      Cheers,

      -stevieb

        BTW, I don't think it is a bad idea to have more Perl tutorials out there. More tutorials means more points of view, more discussion, etc. You can learn from the existing tutorials to make your ones better, but they can also learn from you.

        Part of the success of the Perl community is based on the idea that there are more than one ways to do something, but also that implies we need a multitude of different voices explaining things so people get different understandings.

        So I would not discourage you in any way from continuing to do these tutorials yourself and I look forward to seeing the other parts here.

Re: Tutorial RFC: Guide to Perl references, Part 1
by Monk::Thomas (Friar) on Jul 09, 2015 at 11:54 UTC

    When converting from 'normal' to 'reference' I propose you keep the same value.

    Instead of

    my $x  = $array[0];
    my $y = $aref->1;
    
    change the example to
    my $x = $array[0];
    my $x = $aref->[0];
    

    Otherwise someone who is totally new to references might get the impression you also need to increase the array index by one...

    P.S.: Maybe you should also explain the meaning of 'aref' / 'href'.

      Very keen observation, thanks!

      That's a trivial fix that absolutely makes sense.

      -stevieb

Re: Tutorial RFC: Guide to Perl references, Part 1
by djrosenblatt (Initiate) on May 03, 2019 at 17:01 UTC

    Thank you for this tutorial. You've helped clear up one thing that has probably caused me some confusion when reading others' Perl code, which is that the curly braces have two different purposes. One is to dereference arrays and hashes. For example:

    my @myarray = @{ $aref } ; my %myhash = %{ $href } ;

    The other use is to reference a hash value by means of its key:

    my $hash_value = $myhash{ $keyA } ;

    But is there some consistent logic to this? That is, does the internal Perl logic consider a key of a hash to essentially be a reference to the storage holding its associated value?

    And are there any other "gotchas" in Perl that typically cause confusion in newbies?

    Thanks!

      > curly braces have two different purposes. One is to dereference arrays and hashes. For example

      curly braces have more purposes

      • grouping blocks like if (1) { CODE }
      • literal anonymous hashes $href = { KEY => VALUE }
      • accessing hash keys $href->{KEY} or $hash{KEY}

      This my %myhash = %{ $href } ; is just a form of grouping like in the first example to clarify the precedence.

      Which doesn't make much sense here since my %myhash = %$href ; has the exact same effect.

      And it's not the curly which does the dereference, but the %sigil.

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

Re: Tutorial RFC: Guide to Perl references, Part 1
by pritesh_ugrankar (Monk) on Mar 06, 2017 at 11:55 UTC

    Hi Stevieb,

    Thank you for taking time to write this article. I'm finally able to understand how to reference and derefence. It was tough for me to understand initially, but now it's much clear.

    Thinkpad T430 with Ubuntu 16.04.2 running perl 5.24.1 thanks to plenv!!

      You're welcome.

      Did you find this article here on Perlmonks? Would you recommend that I make all of those posts available here?

        Yes, I did find it on Perlmonks, and yes please if you have not already done it, I would speak in support of including the other 4. Like others, this description helped a good deal. You reminded me of the "cast" syntax of %{ $ref } and others.

        Because the reference looks like a plain scalar, e.g., $starwars one might be tempted to do arithmetic on it (in a module far, far away). $starwars += $Lucas

        I use subroutine signatures when I can. Is there a way to require a reference in the signature? Is this in one of the later parts of your documentation?

        I currently name the variable with a _ref at the end of the name as a reminder, e.g., $starwars_ref

        Reading ahead, I now see that you use _aref, _href, _oref,and _sref.

        Thank you, stevieb

Re: Tutorial RFC: Guide to Perl references, Part 1
by Anonymous Monk on Jul 28, 2015 at 09:20 UTC
    Thank you, my "'Ahhhh' moment of clarity" came while reading your post :-)

      That's awesome :)

      Thanks for commenting!

Re: Tutorial RFC: Guide to Perl references, Part 1
by sundialsvc4 (Abbot) on Jul 08, 2015 at 19:37 UTC

    Two things that I would include in any tutorial on references, and in early installments:

    (1) Reference Counting:   Perl allocates bits of storage for many purposes (including the storing of variables and their values), cleaning them up automatically when they’re no longer being referred-to.   It counts the number of references that currently exist, including both the ones that you create (explicitly), and the ones that it does (implicitly).   (You don’t need to wander off into a discussion of “weak(ened) references.”)

    (2) EQUIVALENCE:   This FORTRAN term might be unknown by now, but it let you say that two variables occupied exactly the same area of storage.   References effectively do the same thing:   if two references exist to the same bit of storage, well, they both refer to one and the same bit of storage!   The Perl language makes it very easy to use references in many powerful ways if you know what you are doing ... and to construct statements (especially, those involving references) which do not actually do or say what you think they do.   In your testing, you need to be sure, both that equivalent-references exist when you think they do, and that values are actually distinct when you expect them to be.

    And here’s the specific reason for these two suggestions:

    (1) If you refer to references as “a pointer to ...” when you are speaking to a programmer who is accustomed to a non-interpreted frame of reference (or, for that matter, even Java), one of two “mental de-railings” might occur.   The “C/C++” bare-metal programmer might not be familiar with this kind of storage-allocation strategy.   Users of other also-interpreted language systems which do not expressly provide for references might also become confused.   (And, in an educational effort like this, “if you lose ’em, they’re gone.”)

    (2) Most of the really-nasty bugs that I have ever had to chase down in (always, someone else’s ...) Perl programs ... have had something to do with precisely this problem.   And, it has certainly “cut both ways.”   Either the programmer meant for the storage to be distinct, or s/he intended for the references to be equivalent.   “Perl compiled the source-code, nonetheless” (even with use strict/warnings), but it did not do what the original-programmer thought it would.

    It’s a delicate balance, of course, as to when and where you want to choose to “refer to the smelly-fish” in an education topic that is basically targeted at newbies.   I generally think that suggestions should be dropped early, so that you can circle-the-wagons to them later on.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://1133627]
Approved by Athanasius
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others browsing the Monastery: (4)
As of 2024-03-19 07:01 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found