coldmiser has asked for the wisdom of the Perl Monks concerning the following question:

Am I the only one that is still having a problem with references? No matter how much information I read about them, they are still out of my reach. I just finished perlref and I'm still having problems with them.

While looking at Crian's post, I'm having trouble getting the second example to work (the first one works correctly) but the second (the second "f" sub) does not print at all.

Am I doing something wrong, or did I overlook something? I copied & pasted his code directly (changing the second "f" subroutine to a "g" for clarity) but it does not work for me.

This is my first programming language so I don't have any other syntax I can fall back on to make sure I am doing these correctly. Coincedently, as I try to pick up C++, I'm also having problems with references. Are there any other good (beginner) tutorials or books on references that I've overlooked?

Ultimately, I would like to pass a couple of arrays to a subroutine compare them, do some other calculations and return multiple arrays back
Something like this:

my @array1 = (0..9); my @array2 = ('a'..'l'); (@a1, @a2) = &f(\@array1, \@array2); print "\@a1 is: @a1\n"; print "\@a2 is: @a2\n"; sub f { my @a1 = @{shift}; my @a2 = @{shift}; ... return (\@a1, \@a2); }

Thanks

Replies are listed 'Best First'.
•Re: Help with references
by merlyn (Sage) on Jul 01, 2004 at 17:02 UTC
    If you had turned warnings on, you'd see that your @{shift} is getting interpreted as @{"shift"} (which would also have been caught by "use strict") instead of @{(shift)}.

    Moral of the story: use strict; use warnings;.

    -- Randal L. Schwartz, Perl hacker
    Be sure to read my standard disclaimer if this is a reply.

Re: Help with references
by Zaxo (Archbishop) on Jul 01, 2004 at 17:06 UTC

    I think you mean to return (@a1,@a2); in f(). As it is, you're taking references to them before passing back the list.

    A side note, the line where you call f() will leave the global @a2 empty. Arrays in multiple assignment are greedy.

    After Compline,
    Zaxo

Re: Help with references
by coldmiser (Hermit) on Jul 01, 2004 at 17:24 UTC
    Coldmiser continues to beat his head against the wall (strict, warnings... must remember strict, and warnings).

    OK, my new code stands as follows:

    #!/path/to/perl -w use strict; my @array1 = (0..9); my @array2 = ('a'..'l'); my (@a1, @a2) = g(\@array1, \@array2); print "\@a1 = @a1\n"; print "\@a2 = @a2\n"; sub g { print "sub g\n"; my @a1 = @{(shift)}; my @a2 = @{(shift)}; print "$_ " for @a1; print "\n"; print "$_ " for @a2; print "\n"; return (@a1, @a2); }

    Anyway to make the global @a2 not empty when I'm done?

    Oh, and thank you both.

      Instead of returning the arrays themselves, you could return references. e.g. return ([@a1],[@a2]); (BUT NOT: return (\@a1, \@a2);) Of course, then you need to be expecting references returned from the function.

      I prefer to call the function in void context (i.e. don't expect anything to be returned from it) and pass in references to the arrays you want to assign to as parameters and then have the function fill them in for you, but this is a matter of style I guess.

      Edit by BazB: add code tags and formatting.

        Why do you recommand against return(\@a1, \@a2)?
Re: Help with references
by derby (Abbot) on Jul 01, 2004 at 17:26 UTC
    Am I the only one that is still having a problem with references? No matter how much information I read about them, they are still out of my reach. I just finished perlref and I'm still having problems with them.

    Do you prefer nice graphics? Effective Perl Programming has a great graphical notation for perl data structures (called PeGS - PErl Graphical Structures). The book used to be available online but that link has been problematic for quite some time. You can check out the Effective Perl course slides here (the PeGS stuff starts on page 55 of the pdf).

    merlyn was a co-author of Effective Perl (merlyn can you shed any light onto what happened to the effectiveperl site?).

    -derby
      can you shed any light onto what happened to the effectiveperl site?
      Well, Joseph still owns the domain, but is getting out of the Perl training business, and into commercial art photography full time and has moved to northern Alaska. I wouldn't be surprised if the site has stopped working as a result.

      -- Randal L. Schwartz, Perl hacker
      Be sure to read my standard disclaimer if this is a reply.

        I wish him all the luck in his new adventure but to be totally selfish, any chance of getting Stonehenge to host the pdf copy of Effective Perl that used to be available at effectiveperl.com?

        -derby
Re: Help with references
by tilly (Archbishop) on Jul 02, 2004 at 01:57 UTC
    References quick reference by tye won't necessarily help you in "getting how references work", but it cuts through the syntax issues for how to try to say what you want to try saying.
Re: Help with references
by gaal (Parson) on Jul 01, 2004 at 22:30 UTC

    *Everybody* has problems with references at first. I think the brain just needs enough headbanging until it reshapes itself somehow. (Many people did this so long ago they don't remember their initial difficulty. This doesn't mean it didn't *use* to hurt, though.)

    Anyway, you might find perlreftut helpful. It's a "kinder, gentler" perlref.

Re: Help with references
by Anonymous Monk on Jul 02, 2004 at 00:47 UTC

    I wont reiterate the importance of 'strict' and 'warnings' ... (it is very useful) instead, I'm gonna tell you what you won't hear from anyone else.

    I post this because you said this is your first programming language. Others will disagree with what I am about to tell you, and this may seem like weird advice, but you can judge for yourself. ... Disclaimer: extremely biased opinion follows ... IMHO the single best way to 'wrap your brain' around working with references is to absolutely avoid using the 'backslash notation' whenever possible, and just treat everything as a scalar. This may take a moment to sink in, but let me explain, and consider this example ...

    ### re-worked version of your original code my $ref1 = [(0..9)]; ### start with anon array refs my $ref2 = [('a'..'l')]; ### from the very beginning my ($aOne, $aTwo) = &f($ref1, $ref2); print '@a1 is: '. "@{$aOne}\n"; print '@a2 is: '. "@{$aTwo}\n"; sub f { my $a1 = shift || die 'Hey! I expected an array ref '; my $a2 = shift || die 'expected array ref here too '; ### do something, for example ... @{$a2} = reverse @{$a2}; return ($a1, $a2); } __END__ @a1 is: 0 1 2 3 4 5 6 7 8 9 @a2 is: l k j i h g f e d c b a

    rationale

    • the little 'backslash notation' just sucks. It is ugly, it is error prone, it is confusion-inducing, and it is one of the worst widespread typographical conventions in the entire field of computer programming. Avoid using it with your variables. (aside from stuff like \n, which is basically a constant) Your brain will thank you for it.
    • just think to yourself "scalars can hold *anything*", not just strings ... then you realize the hardest part is just picking a variable name (eg $ref1, $aryRef1, $hashRef1, $bigHugeNestedVariable1, etc) to remind you of what that scalar is expected to be holding
    • suppose you want to change your arrays to hashes or something else? It's a PITA to go around changing all those little \@ symbols to \% symbols, and much clearer to change 'die expected array ref' to 'die expected hash ref'. Either way, you will have to change the code, but one set of changes is easier on the cognitive process than the other. You can decide for yourself which ones.

    Just remember: 1) "scalars can hold anything" (the variables with the dollar sign in front) use them; 2) give those scalars a good name to reflect what's expected of them; and 3)properly 'morph' those scalars into proper versions of what they are holding with @{$foo}, @$foo, %{$foo}, or %$foo, notation .. or $foo->(), $foo->{baz}{blee}{blaa}( or whatever else is appropriate ) and you're done.

      I agree that it's easier to use references throughout your program, rather than having to deal with real arrays and references to arrays. The same applies to hashes. One other thing is that you can use the arrow operator to index into the array refererence with square brackets, as the example below demonstrates. You can do a similar thing with hash references.
      #!/usr/bin/perl use strict; use warnings; run(); sub run { my $arr1 = [0 .. 12]; my $arr2 = ['a' .. 'l']; print "before:\n"; print "arr1 = @{$arr1}\n"; print "arr2 = @{$arr2}\n"; # because we're passing references to arrays, any changes # made to the arrays in the subroutine will affect the arrays # here as well. No need to return the arrays. f($arr1, $arr2); # use the arrow operator and square brackets to index the # array, same as in the subroutine below - same syntax, # less confusing $arr1->[7] = "SEVEN!"; print "after:\n"; print "arr1 = @{$arr1}\n"; print "arr2 = @{$arr2}\n"; } sub f { my ($arr1, $arr2) = @_; for (my $i = 0; $i < 5; $i++) { # shuffle some stuff around my $index1 = rand($#$arr1); my $index2 = rand($#$arr2); # use the arrow operator and square brackets to index # the array through a reference my $tmp = $arr1->[$index1]; $arr1->[$index1] = $arr2->[$index2]; $arr2->[$index2] = $tmp; } }