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

'my' buggy...

by december (Pilgrim)
on Apr 30, 2002 at 16:04 UTC ( [id://163102]=perlquestion: print w/replies, xml ) Need Help??

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

Hi,

I have a little problem with 'my' behaving weird... or at least, that's what I think it is.

sub showCat { my ($cat) = @_ if @_; local (*DIR, *HTML); my (@piclist); my ($pic, $template, $__atom__, $__catname__); my ($i) = 0; [...] $__atom__ .= '</table>'; $template =~ s/\$(\w+)/${$1}/g; print $template; }

The template contains $__atom__, the variable is found, the left hand of the substition works fine, but the right hand thinks the variable is empty (while it's _not_). If I don't declare $__atom__ or use local, everything works fine. As this line is clearly within the scope of $__atom__, and the variable does exist (aswell before as after the substitution), this seems like a problem with 'my'...

Can someone confirm if this is a bug, or am I doing something secretly wrong here...


Thanks!

__ december

Replies are listed 'Best First'.
Re: 'my' buggy...
by Fletch (Bishop) on Apr 30, 2002 at 16:09 UTC

    You're attempting to use a symref to access a lexical variable, which won't work since lexicals don't reside in the symbol table. This won't work either:

    $ perl -le 'my $foo = 5; print ${"foo"}' $

    A use strict would have produced a gripe.

      What is the correct way to access a lexical variable in a simple substitution then?...
        From the Perl FAQ, $text =~ s/(\$\w+)/$1/eeg;

        _____________________________________________________
        Jeff[japhy]Pinyan: Perl, regex, and perl hacker, who'd like a (from-home) job
        s++=END;++y(;-P)}y js++=;shajsj<++y(p-q)}?print:??;

Re: 'my' buggy...
by Elian (Parson) on Apr 30, 2002 at 16:16 UTC
    There may well be a bug there, but it might also be a result of this:
      my ($cat) = @_ if @_;
    
    If @_ is empty, $cat will have the value it had the last time you were in the block. This is due to the way perl reuses scratchpads on block entry. Every sub (not every block, mind, but every sub) has a scratchpad associated with it, with space for all the my'd variables reserved in it. If, at runtime, you enter that sub and the default scratchpad isn't in use (because of recursive calls, for example) perl will use the default scratchpad. This saves on time, as the assumption is you won't be recursive and you will enter a sub more than once over the run of the program. Reusing the scratchpad means no time spent to allocate memory each time through.

    The interesting bit is that initialization--giving the variables in the scratchpads values--is a runtime thing. Perl doesn't give a default to variables that have values assigned as part of the my, as that'd be a waste of time as well. (Why assign a default that's going to be immediately overwritten?) But your assignment is conditional, and in some cases it won't happen. That means that in those cases where the condition on the initial assignment isn't met no assignment happens at all. And, since perl's reusing scratchpads, you'll just get whatever was in there from the last time around.

    Needless to say, this is often not what you want.

      Not true (try it). The weirdness only exists when the condition is false at compile-time -- e.g., when a constant like 0 is used.

      _____________________________________________________
      Jeff[japhy]Pinyan: Perl, regex, and perl hacker, who'd like a (from-home) job
      s++=END;++y(;-P)}y js++=;shajsj<++y(p-q)}?print:??;

        Umm.... no.
        sub foo {
            my $baz = 12 if @_;
            print "$baz\n";
            $baz++;
        }
        
        foo(1);
        foo();
        foo();
        foo();
        foo(1);
        foo();
        foo();
        foo();
        
        Produces
        12
        
        1
        2
        12
        
        1
        2
        
        You don't really think I'd not check, do you? :)
Re: 'my' buggy...
by Molt (Chaplain) on Apr 30, 2002 at 16:12 UTC

    I'm wondering if this is something to do with the wonderous 'static my' trick. Essentially putting 'my $var if 0' has an odd effect, the compiler phase sees it so $var is indeed localised, but the interpreter phase doesn't see it so it's never initialised to zero(!).

    The result? An ugly equivilence of static variables where it maintains it's value between calls.

    With yours I think it'll be maintaining it's value from the previous call unless it's passed a parameter. Probably not what you wanted. Try..

    my $cat; $cat = @_ if @_;

    It may work.. I think this is a case of what you don't know hurting you, unfortunately.

    Just found this old bit of code I knocked out to test the 'static my' effect. Think it makes things clear.

    #!/usr/bin/perl -w use strict; for (my $i=0; $i<10; $i++) { count(); } sub count { my $count=0 if 0; print "Called $count times\n"; }
Re: 'my' buggy...
by Molt (Chaplain) on Apr 30, 2002 at 16:37 UTC

    Okay, had a proper bit of playing with this and it's looking like the symbolic reference is getting the global value. As an example look at the code below.. uncomment as needed!

    #!/usr/bin/perl $::test = 'Global'; test(); sub test { my $test = 'Local'; my $line = 'test'; # This returns 'Global'. # print ${$line}."\n"; # This returns 'local' # $line =~ s/\w+/${test}/gi; # This returns 'Global' # $line =~ s/(\w+)/${$1}/gi; print "$line..\n"; }

    Does anyone know if this is a known thing with symbolic references? Does it effectively do a $::test?

      Symbolic references only access globals. Nature of the beast. The only way to access lexicals by name at runtime, short of walking the pad, is with string eval, and that's not always 100% reliable.
Warning about the 'my $var if 0' trick.
by Molt (Chaplain) on May 01, 2002 at 14:33 UTC

    Since some people, including me, initially wrongly thought the problem here was the 'my' declaration and pointed out the ugly my trick I ended up looking through to find out where it was I first learnt about it.

    It turned out to be in Exegesis 4, and now having read it again I find it came with a link to a warning about the 'my trick'. Since some may read this and think 'Hey, neat trick.. I didn't know that' I thought putting the warning here was in order.

    It reads as follows.

    NOTE: The behaviour of a my statement modified with a statement modifier conditional or loop construct (e.g. my $x if ...) is undefined. The value of the my variable may be undef, any previously assigned value, or possibly anything else. Don't rely on it. Future versions of perl might do something different from the version of perl you try it out on. Here be dragons.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others surveying the Monastery: (8)
As of 2024-04-24 11:36 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found