Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

Dereference string in foreach

by Anonymous Monk
on Feb 13, 2013 at 20:02 UTC ( [id://1018620]=perlquestion: print w/replies, xml ) Need Help??

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

I have a question on a problem that occured in v5.12.4 using Ubuntu:

My code makes it neccessary to loop through an array and to output all elements using a reference. My first try did not work as expected (simplyfied example):

$sref = \$string; foreach $string ( @array_of_strings ) { print $$sref; }
However, the following code does work (and is my solution):
$sref \$string1; foreach $string2 ( @array_of_strings ) { $string1 = $string2; print $$sref; }
Why? I would have expected that using the foreach $string acutally is assigned to whatever is the element of the array but aparently this is not the case. In the first example the print will only print what was assigned to $string before executing the foreach loop. Of course my actual code isn't that simple.

Replies are listed 'Best First'.
Re: Dereference string in foreach
by 7stud (Deacon) on Feb 13, 2013 at 23:23 UTC

    By the way, in "Perl Best Practices" Damian Conway advises that you should always write 'my' before your for-loop variable because if you don't :

    [The resulting] behaviour is contrary to all reasonable expectation.  Everywhere else in Perl, when you declare a lexical variable, it's visible throughout the remainder of its scope, unless another explicit my declaration hides it.  So it's natural to expect that the [variable] used in the for loop is the same lexical [variable] that was declared before the loop.
    
    But it isn't.
    
    ("Perl Best Practices", p. 108)

    My code makes it neccessary to loop through an array and to output all elements using a reference.

    That doesn't seem to make a lot of sense:

    use strict; use warnings; use 5.010; my @arr = (10, 20, 30); for my $num (@arr) { say ${\$num}; } --output:-- 10 20 30
Re: Dereference string in foreach
by choroba (Cardinal) on Feb 13, 2013 at 21:05 UTC
    See Foreach Loops. If the variable is not declared with my, it is implicitly localized. For each iteration, the variable is aliased to the value you are looping over. Therefore, in the first case, the loop variable $string is a different one than the $string defined before the loop: Try
    $sref = \$string; foreach $string ( @array_of_strings ) { print $sref, \$string, "\n"; }
    In the second snippet, you are using $string1 which is not localized. Therefore, $ref really points to it, and since you assign the value from the loop variable to it, you can acces the value by the reference. Note, though, that this is only a copy of the original value, which means you cannot change the original @array_of_strings by changing $$ref or $string1, but only $string2.
    لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ

      Here is the effect when perl localizes a variable:

      #Whoops.  An Anonymous Monk already posted a good example.

      And because a for loop aliases each element in the array to the loop variable, changes to the loop variable change the elements of the array.

Re: Dereference string in foreach
by blue_cowdawg (Monsignor) on Feb 13, 2013 at 20:28 UTC
        Why? I would have expected that using the foreach $string acutally is assigned to whatever is the element of the array but aparently this is not the case.

    Turn on strict and warnings and you'll see why.

    use warnings; use strict; my $sref = \$string; foreach $string ( @array_of_strings ) { print $$sref; } $ perl sref_o.pl Global symbol "$string" requires explicit package name at sref_o.pl li +ne 4. Global symbol "$string" requires explicit package name at sref_o.pl li +ne 5. Global symbol "@array_of_strings" requires explicit package name at sr +ef_o.pl line 5. Execution of sref_o.pl aborted due to compilation errors.


    Peter L. Berghold -- Unix Professional
    Peter -at- Berghold -dot- Net; AOL IM redcowdawg Yahoo IM: blue_cowdawg

      You don't need to be an utter cowdawg towards the OP -- strict and warnings are irrelevant to his issue.

      I don't fully grok the semantics of foreach but I suspect the correct answer is as follows:

      $sref = \$string sets $sref to point to the variable $string. All is well here. But then foreach enters the picture and localises $string -- this $string is only available to the inner loop. $sref continues pointing to the $string in the outer loop. Testing this without the string reference:

      my $string = "I'm still here"; say $string; my @array_of_strings = qw/foo bar baz quux/; foreach $string ( @array_of_strings ) { say $string; } say $string; # output I'm still here foo bar baz quux I'm still here

      Yep, looks like what I described. Now, if you add the $sref, you'll notice it'll print the outer loop value for the whole time -- it points to the wrong $string.

        Thanks for that answer.
        Though quite some time has passed since I last read the corresponding paragraph in perldoc, I wouldn't have expected that the reference still points to the variable outside of the loop since it is used within the loop.

        All variables have been previouly defined using my (i.e. in the beginning of the script).

            You don't need to be an utter cowdawg towards the OP -- strict and warnings are irrelevant to his issue.

        I wasn't being mean, ornery or cantankerous. Take what I said at face value. If strict and warnings were turned on (as I showed) the problem would have shown itself very clearly.


        Peter L. Berghold -- Unix Professional
        Peter -at- Berghold -dot- Net; AOL IM redcowdawg Yahoo IM: blue_cowdawg

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others examining the Monastery: (8)
As of 2024-03-28 09:16 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found