Discussions
Categories
Groups
Community Home
Categories
INTERNAL ENABLEMENT
POPULAR
PUBLIC CLOUD
PRIVATE CLOUD
Quick Links
MY LINKS
HELPFUL TIPS
Back to website
Home
Web CMS (TeamSite)
Scope mystery
System
I ran into an odd problem with lexical scoping today, and I don't understand it. Here is a corrected test script that (mostly - still have to get the interpolation of the newline happening) works:
my $string = 'Hey there, $name\nThis is a $what\n';
local $name = "Bubba";
local $what = "test";
$string =~ s/\$(\w+)/${$1}/ge;
print $string . "\n";
What I don't understand is that if use my to lexically scope $name and $what, it fails to derefence them in the substitution. It's obviously a scope problem, so I very quickly thought to use local instead of my, but this doesn't conform to any of the cases listed in the perlsub manpage as far as situations where it should be necessary to use local.
Can someone school me on this?
Find more posts tagged with
Comments
Dwayne
My guess is that you're executing this code multiple times, right? The code, as you've written it, tries to interpolate before you've assigned the values. In the case of 'my' variables, that pretty much guarantees that the value will be undefined. However, 'local' behaves differently. It 'hides' the variable from other scopes, but it doesn't create a new instance each time it is encountered. 'local' is more like a global variable under a witness protection program than a truely local variable in the normal sense of the word.
Migrateduser
To throw another data point on there, I coded a similar test to see what would happen with just an eval, not worrying about whether I was in a substitution or not - the behaviour is exactly the same.
local $name2 = "Earl";
my $ref = "name2";
eval { print ${$ref}; };
works, but
my $name2 = "Earl";
my $ref = "name2";
eval { print ${$ref}; };
does not.
I'm thinking that this is essentially the same case as why one has to use local rather than my to scope special variables like $/ and so forth. It's an intricacy of the interpreter that I don't entirely understand, but it involves some things not being accessible during the lexical analysis of the script that are accessible post-compilation.
Migrateduser
Bzzt, wrong answer -
Notice that those are single quotes, so there is no interpolation happening. Rather I'm taking a literal string which includes literal dollar signs and such, and then in the substitution, capturing those and trying to replace them using "soft" references.
It doesn't seem to me in this context that my vs. local should make a difference since the eval is within the scope where the variable is declared. All I can figure is that the variables "go away" after the lexical analysis phase of the compilation, but I haven't read Aho's book in who knows how long, and I sure haven't taken the time to look through the code for the perl interpreter.
Dwayne
You're right - i didn't read closely enough. That will teach me. I'll go back to my cave now.
--
Current project: TS 5.5.1/6.1 W2K
Adam Stoller
While potentially an interesting exercise for delving into the mysterious depths of Perl - what exactly are you trying to accomplish? From the examples you've shown, I can guess at what you're trying to do and can think of a number of reasonably straight-forward ways to code it - but without really knowing what you're doing and/or not having more context with respect to how you're trying to do it - it's not worth posting random solutions (IMO)
--fish
Senior Consultant, Quotient Inc.
http://www.quotient-inc.com
bboyle
$string =~ s/\$(\w+)/${$1}/ge;
would this work instead?
$string =~ s/(\$\w+)/$1/ge;
$1 should be the variable name ($name and $what, respectively) and the eval modifier should return the value ...?
Migrateduser
I need to instantiate a child job by making some substitutions in a job spec and then doing an iwjobc -i against it. You've probably noticed that I try a slightly different approach to this every year or so (like my command line wft compiler from back in '02), bc I haven't really hit upon a solution that completely floats my boat. My current approach is to put perl variables in the file and do the substitutions - the idea is that then anything that was within the current scope in the .ipl could be inserted into the job spec via regex - eventually if I make it smart enough, I could even put perl expressions directly in the job spec.
In short, it's yet another version of an external task that I end up needing everywhere I go. My goal is to get it so reuseable that I never have to touch the code of the external task itself again.
Migrateduser
> would this work instead?
> $string =~ s/(\$\w+)/$1/ge;
>
> $1 should be the variable name ($name and $what, respectively) and the eval modifier should return the value ...?
No dice - that just gives me the original string.
Hey there, $name\nThis is a $what\n
Your reasoning seems sound though.
Migrateduser
I think I might have found my answer - soft refs are not allowed under use strict now according to perlfaq7 (is that something new with 5.8 - I've been stuck on projects using 5.005_03 for 2 years now and forgot all the changes). Odd that it doesn't throw a warning though.
There's even an exact example of what I'm trying to do:
$str = 'this has a $fred and $barney in it';
$str =~ s/(\$\w+)/$1/eeg; # need double eval
Of course, this is accompanied with dire warnings to the effect of "You should never do this unless you are a complete moron", but I may choose to ignore those. Or, I could be a good boy and load everything I'm ever likely to use into a hash.
Of course, for maximum reusability, I could put the any variables I'm likely to use into job variables, and make an appropriate call to GetVariable() in my eval. If I paired that with a function to initialise and provide sensible values for any of the common things if they don't get passed in as a task variable, I could really be on to something. I think that's what I'm going to do.
Adam Stoller
If you're working with TS6 - which has the later version of Perl - use should use the following two prgamas:
use strict;
use warnings;
The second one is a [better] replacement for the old '-w' flag.
--fish
Senior Consultant, Quotient Inc.
http://www.quotient-inc.com
Migrateduser
I was - I just had a cranial infarction and forgot that I had temporarily commented them out while I was messing with this last week (gee, maybe that's why it wasn't throwing warnings).