Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

Scalar Value Not Available To Subroutine

by Anonymous Monk
on Dec 20, 2012 at 16:33 UTC ( [id://1009757]=perlquestion: print w/replies, xml ) Need Help??

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

I am quite sure there is a simple reason for this but it is beyond me. The code below prints the uid as expected from within the foreach loop. However, it will not print it in the subroutine. Why not and how can I fix it?
#!/usr/bin/perl use strict; my $uid; my @array = ("one","two","three"); foreach $uid (@array){ print "uid in loop=$uid\n"; # prints each value of $uid as expected &mail($uid); } sub mail { # never prints the value of $uid ? ? print "uid in sub=$uid\n"; }
Thank you!

Replies are listed 'Best First'.
Re: Scalar Value Not Available To Subroutine
by BrowserUk (Patriarch) on Dec 20, 2012 at 17:23 UTC
    The code below prints the uid as expected from within the foreach loop. However, it will not print it in the subroutine. Why not and how can I fix it?

    The reason is that the foreach loop localises $uid; but the subroutine mail closes over the variable declared above and outside the foreach loop, which is never initialised or assigned to.


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

    RIP Neil Armstrong

      So loop "localisation" is different to the "localisation" done by local?

      #!/usr/bin/perl use strict; our $uid; my @array = ("one","two","three"); for (my $i = 0; $i < @array; $i++) { local $uid = $array[$i]; print "uid in loop=$uid\n"; # prints each value of $uid as expected mail($uid); } sub mail { # never prints the value of $uid ? ? print "uid in sub=$uid\n"; }
      perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'

        Seems so. Effectively, the loop variable has no relationship with any pre-existing variable with the same name:

        my $i; for $i ( 1..10 ){ 1; }; print $i };; Use of uninitialized value $i in print at (eval 9) line 1, <STDIN> lin +e 1.

        I believe it is a throw-over from pre-lexical Perl.

        I've often wished (and occasionally argued in favour of), that for didn't localise pre-existing, lexical loop variables.

        It makes for messy workarounds to the situation where a counting loop can exit early conditionally, and you want to know how far it counted:

        my $i; for $i ( 1 .. $N ) { last if <SOMECOND>; ... } ## Here we have no way of knowing if we took an early exit; ## thus necessitating additional, unnecessary complexity to retain or +discover that.

        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.

        RIP Neil Armstrong

        > So loop "localisation" is different to the "localisation" done by local?

        yes and no, since (unfortunately) you can't use local with lexicals!

        But foreach tries to mimic this behaviour (a tribute to DWIM)

        As you can see localization is as predicted with package vars, but seems to rebind the var to the new pad for lexical vars.

        lanx@ubuntu:~$ perl our $i; for $i (1..9) { tst(); } sub tst { print $i; } 123456789 lanx@ubuntu:~$ perl my $i=42; for $i (1..9) { tst(); } sub tst { print $i; } 424242424242424242

        we already had similar discussions.

        Cheers Rolf

        So loop "localisation" is different to the "localisation" done by local?

        No, the difference you are seeing is because subs capture lexical vars but not package vars.

Re: Scalar Value Not Available To Subroutine
by LanX (Saint) on Dec 20, 2012 at 16:40 UTC
    sub mail { my ($uid) = @_; # <-- assign argument print "uid in sub=$uid\n"; }

    it maybe worked before because you also filescoped a $uid, but after passing it to the routine as argument you should also assign it.

    EDIT: At least that may be the reason why strict didn't complain. Anyway in many aspects your code is too weird for me to try it out.

    Cheers Rolf

Re: Scalar Value Not Available To Subroutine
by tobyink (Canon) on Dec 20, 2012 at 17:13 UTC

    It seems that $uid should be visible and defined in the sub. The lexical scope of the $uid variable ought to cover the sub, and the dynamic scope of the loop should cover the calls to the sub. Odd; I can't say I exactly understand what's happening here.

    Works if you do our $uid though.

    perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others cooling their heels in the Monastery: (4)
As of 2024-04-25 05:59 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found