Perl eval scope - perl

According to perldoc, String Eval should be performed in the current scope. But the following simple test seems to contradict this.
We need the following two simple files to set up the test. Please put them under the same folder.
test_eval_scope.pm
package test_eval_scope;
use strict;
use warnings;
my %h = (a=>'b');
sub f1 {
eval 'print %h, "\n"';
# print %h, "\n"; # this would work
# my $dummy = \%h; # adding this would also work
}
1
test_eval_scope.pl
#!/usr/bin/perl
use File::Basename;
use lib dirname (__FILE__);
use test_eval_scope;
test_eval_scope::f1();
When I run the program, I got the following error
$ test_eval_scope.pl
Variable "%h" is not available at (eval 1) line 1.
My question is why the variable %h is out of scope.
I have done some modification, and found the following:
If I run without eval(), as in the above comment, it will work.
meaning that %h should be in the scope.
If I just add a seemingly useless mentioning in the code, as in the above
comment, eval() will work too.
If I combine pl and pm file into one file, eval() will work too.
If I declare %h with 'our' instead of 'my', eval() will work too.
I encountered this question when I was writing a big program which parsed user-provided code during run time. I don't need solutions as I have plenty workarounds above. But I cannot explain why the above code doesn't work. This affects my perl pride.
My perl version is v5.26.1 on linux.
Thank you for your help!

Subs only capture variables they use. Since f1 doesn't use %h, it doesn't capture it, and %h becomes inaccessible to f1 after it goes out of scope when the module finishes executing.
Any reference to the var, including one that's optimized away, causes the sub to capture the variable. As such, the following does work:
sub f1 {
%h if 0;
eval 'print %h, "\n"';
}
Demo:
$ perl -M5.010 -we'
{
my $x = "x";
sub f { eval q{$x} }
sub g { $x if 0; eval q{$x} }
}
say "f: ", f();
say "g: ", g();
'
Variable "$x" is not available at (eval 1) line 1.
Use of uninitialized value in say at -e line 8.
f:
g: x

Related

Escaping semi-colon syntax in Perl

How can I escape a semi-colon (that's syntax ) in perl by only adding characters after it?
Say I have a line of code:
print "foo";
I want to add the following code after it so it can repeat 5 times:
print "foo"; x 5;
Is there anyway I can escape/ignore the semicolon (without altering the original piece of code) so it can be interpreted as:
print "foo" x 5;
Edit: This seems like too much of a hassle, better off to just nest the line in a for loop.
Seems like you just want to print "foo" 5 times ?
If yes, then :
use strict;
use warnings;
print "foo" for (1..5);
Yields :
foofoofoofoofoo
Here is an example using a source filter.
In fact it alters the code before executing it so you don't have to do it yourself.
echo package FiveTimes; use Filter::Simple sub{s/;/x5;/g};1; > FiveTimes.pm
perl -MFiveTimes -e"print qq/foo/;"
foofoofoofoofoo
print "foo"; BEGIN{tie *STDOUT,'FiveTimer';sub FiveTimer::TIEHANDLE{bless{},'FiveTimer'}sub FiveTimer::PRINT{CORE::print STDERR $_[1] x 5}}
or more readably
print "foo"; BEGIN{ tie *STDOUT,'FiveTimer' }
sub FiveTimer::TIEHANDLE{bless{},'FiveTimer'}
sub FiveTimer::PRINT{CORE::print STDERR $_[1] x 5}}

Why is my localized redefinition of a package sub not taking effect?

Given the following Perl program:
package Foo;
use strict;
use warnings;
sub new {
my ($class) = #_;
return bless {}, $class;
}
sub c {
print "IN ORIG C\n";
}
sub DESTROY {
print "IN DESTROY\n";
c();
}
1;
package main;
use strict;
use warnings;
no warnings qw/redefine once/;
local *Foo::c = sub { print "IN MY C\n" };
my $f = Foo->new();
undef $f;
I expect output as:
IN DESTROY
IN MY C
But I actually get output as:
IN DESTROY
IN ORIG C
Q: Why is my localized redefinition of Foo::c not taking effect?
When perl code is compiled, globs for package variables/symbols are looked up (and created as necessary) and referenced directly from the compiled code.
So when you (temporarily) replace the symbol table entry for *Foo::c at runtime, all the already compiled code that used *Foo::c still uses the original glob. But do/require'd code or eval STRING or symbolic references won't.
(Very similar to Access package variable after its name is removed from symbol table in Perl?, see the examples there.)
This is a bug in perl which will be fixed in 5.22 (see Leon's comment below).
This happens because undef $f; doesn't actually free up and destroy $f, it just marks it as ready to
be freed by a nextstate op.
nextstate ops exist roughly between each statement, and they are there
to clean up the stack, among other things.
In your example, since undef $f is the last thing in the file, there
is no nextstate after it, so your local destructor goes out of scope
before $f's destructor is called (or, the global destruction that
happens just isn't aware of your local change.)
When you add a print statement after undef $f, the nextstate op
before the print calls your local destructor.
You can see the additional nextstate in your example at
https://gist.github.com/calid/aeb939147fdd171cffe3#file-04-diff-concise-out.
You can also see this behaviour by checking caller() in your DESTROY method:
sub DESTROY {
my ($pkg, $file, $line) = caller;
print "Destroyed at $pkg, $file, $line\n";
c();
}
mhorsfall#tworivers:~$ perl foo.pl
Destroyed at main, foo.pl, 0
IN DESTROY
IN ORIG C
mhorsfall#tworivers:~$ echo 'print "hi\n"' >> foo.pl
mhorsfall#tworivers:~$ perl foo.pl
Destroyed at main, foo.pl, 30
IN DESTROY
IN MY C
hi
(Line 30 being the print "hi\n")
Hope that sheds some light on this.
Cheers.
The problem here doesn't have to do with compile time vs runtime but rather with scoping.
The use of local limits the scope of your modified Foo::c to the remainder of the current scope (which in your example is the remainder of your script). But DESTROY doesn't run in that scope, even when you explicitly undef $f (See http://perldoc.perl.org/perlobj.html#Destructors for more discussion of the behavior of DESTROY). It runs at an undetermined time later, specifically AFTER $f has "gone out of scope". Therefore, any localized changes you have made in the scope of $f will not apply whenever DESTROY finally runs.
You can see this yourself by simply removing the local in your example:
With local
IN DESTROY
IN ORIG C
Without local
IN DESTROY
IN MY C
Or by adding a few additional subroutines and calling them in package::main scope:
package Foo;
...
sub d {
c();
}
sub DESTROY {
print "IN DESTROY\n";
c();
}
1;
package main;
...
sub e {
Foo::c();
}
local *Foo::c = sub { print "IN MY C\n" };
my $f = Foo->new();
Foo::c();
Foo::d();
e();
undef $f;
Which prints
IN MY C
IN MY C
IN MY C
IN DESTROY
IN ORIG C
So only in DESTROY is the original c used, further demonstrating that this is a scoping issue.
Also see https://stackoverflow.com/a/19100461/232706 for a great explanation of Perl scoping rules.

2 Sub references as arguments in perl

I have perl function I dont what does it do?
my what does min in perl?
#ARVG what does mean?
sub getArgs
{
my $argCnt=0;
my %argH;
for my $arg (#ARGV)
{
if ($arg =~ /^-/) # insert this entry and the next in the hash table
{
$argH{$ARGV[$argCnt]} = $ARGV[$argCnt+1];
}
$argCnt++;
}
return %argH;}
Code like that makes David sad...
Here's a reformatted version of the code doing the indentations correctly. That makes it so much easier to read. I can easily tell where my if and loops start and end:
sub getArgs {
my $argCnt = 0;
my %argH;
for my $arg ( #ARGV ) {
if ( $arg =~ /^-/ ) { # insert this entry and the next in the hash table
$argH{ $ARGV[$argCnt] } = $ARGV[$argCnt+1];
}
$argCnt++;
}
return %argH;
}
The #ARGV is what is passed to the program. It is an array of all the arguments passed. For example, I have a program foo.pl, and I call it like this:
foo.pl one two three four five
In this case, $ARGV is set to the list of values ("one", "two", "three", "four", "five"). The name comes from a similar variable found in the C programming language.
The author is attempting to parse these arguments. For example:
foo.pl -this that -the other
would result in:
$arg{"-this"} = "that";
$arg{"-the"} = "other";
I don't see min. Do you mean my?
This is a wee bit of a complex discussion which would normally involve package variables vs. lexically scoped variables, and how Perl stores variables. To make things easier, I'm going to give you a sort-of incorrect, but technically wrong answer: If you use the (strict) pragma, and you should, you have to declare your variables with my before they can be used. For example, here's a simple two line program that's wrong. Can you see the error?
$name = "Bob";
print "Hello $Name, how are you?\n";
Note that when I set $name to "Bob", $name is with a lowercase n. But, I used $Name (upper case N) in my print statement. As it stands, now. Perl will print out "Hello, how are you?" without a care that I've used the wrong variable name. If it's hard to spot an error like this in a two line program, imagine what it would be like in a 1000 line program.
By using strict and forcing me to declare variables with my, Perl can catch that error:
use strict;
use warnings; # Another Pragma that should always be used
my $name = "Bob";
print "Hello $Name, how are you doing\n";
Now, when I run the program, I get the following error:
Global symbol "$Name" requires explicit package name at (line # of print statement)
This means that $Name isn't defined, and Perl points to where that error is.
When you define variables like this, they are in scope with in the block where it's defined. A block could be the code contained in a set of curly braces or a while, if, or for statement. If you define a variable with my outside of these, it's defined to the end of the file.
Thus, by using my, the variables are only defined inside this subroutine. And, the $arg variable is only defined in the for loop.
One more thing:
The person who wrote this should have used the Getopt::Long module. There's a major bug in their code:
For example:
foo.pl -this that -one -two
In this case, my hash looks like this:
$args{'-this'} = "that";
$args{'-one'} = "-two";
$args{'-two'} = undef;
If I did this:
if ( defined $args{'-two'} ) {
...
}
I would not execute the if statement.
Also:
foo.pl -this=that -one -two
would also fail.
#ARGV is a special variable (refer to perldoc perlvar):
#ARGV
The array #ARGV contains the command-line arguments intended for the
script. $#ARGV is generally the number of arguments minus one, because
$ARGV[0] is the first argument, not the program's command name itself.
See $0 for the command name.
Perl documentation is also available from your command line:
perldoc -v #ARGV

How can I use "member" variables of a module inside a function?

I have this code:
#!/usr/bin/perl
package Modules::TextStuff;
use strict;
use warnings;
use Exporter;
our #ISA = qw(Exporter);
our #EXPORT = qw(get_text);
my $author;
my $text_tmp1 =<<'ENG';
This is a template text
by $author.
ENG
sub get_text {
my $tmp = shift #_;
$author = shift #_;
print "In sub author= $author lang = $tmp \n";
my $final_str = eval('$text_'.$tmp);
print "$final_str \n";
return $final_str;
}
1;
Test script:
#!/usr/bin/perl
use strict;
use warnings;
use Modules::TextStuff;
my $str = get_text('tmp1','jim');
print $str;
When I run the test script it does not work. I get:
In sub author=jim lang = eng
Variable "$text_tmp1" is not available at (eval 1) line 2. Use of
uninitialized value $final_str in concatenation (.) or string
How can I fix this?
Combining strings to create variables names is usually a bad idea. You could salvage your current program using our $text_tmp1 = ... instead of my $text_tmp1 = ..., but I think you should consider a different approach, like a hash:
my %templates = (
tmp1 => <<ENG,
This is a template text
by \$author.
ENG
tmp2 => <<ESP,
Esta es templata texta de \$author.
ESP
);
sub get_text {
...
my $final_str = eval( $templates{$tmp} );
...
}
The error you asked about is generated when eval EXPR tries to grab the value of a variable that did exist, but no longer exists.
>perl -wE"{ my $x = 123; sub f { eval '$x' } } say '<'.f().'>';"
Variable "$x" is not available at (eval 1) line 2.
Use of uninitialized value in concatenation (.) or string at -e line 1.
<>
Remember, executing a file (such as a script or a module) is done in its own a lexical scope, just like the one the curlies create above.
It can be fixed by keeping the variable alive by not letting it go out of scope
>perl -wE"my $x = 123; sub f { eval '$x' } say '<'.f().'>';"
<123>
But that's not an option for you.
Other options include making the variable a global variable.
>perl -wE"{ our $x = 123; sub f { eval '$x' } } say '<'.f().'>';"
<123>
Or forcing the sub to capture it so it doesn't cease to exist.
>perl -wE"{ my $x = 123; sub f { $x if 0; eval '$x' } } say '<'.f().'>';"
<123>
(The if 0 silences the "void context" warning.)
That said, it looks like you're trying to re-invent the wheel. Don't invent another half-assed templating system.
I'm looking at several things:
First of all, $text_tmp1 is not a package variable. It's lexically scoped since you declared it with my. If you need it as a package variable and for it to be visible in all or your subroutines, you need to declare it with our.
Your module doesn't compile as written. You are trying to source in $author, but it's not defined.
What are you doing with eval? This is wrong on so many levels.
Here's how I would do it:
#! /usr/bin/env perl
package Modules::TextStuff;
use strict;
use warnings;
use Exporter qw(import);
use Carp;
our #EXPORT_OK = qw(get_text);
our %templates; # This is now a package variable
#
# TEMPLATES
#
$templates{tmp1}=<<TEMPLATE; # We'll use `%s` for replacements
This is a template text
by %s.
TEMPLATE
$templates{tmp2}=<<TEMPLATE;
This is another template and we will substitute
in %s in this one too.
TEMPLATE
sub get_text {
my $template = shift;
my $author = shift;
if ( not exists $templates{$template} ) {
croak qq(Invalid template name "$template");
}
return sprintf $templates{$template}, $author;
}
1;
I'll make each of these templates an entry in my %templates hash. No need for eval to calculate out a variable name for the template. Also notice that I can now actually test whether the user passed in a valid template or not with the exists.
Also note that %template is declared with our and not my. This makes it available in the entire package including any subroutines in my package.
I also use #EXPORT_OK instead of #EXPORT. It's considered more polite. You're requesting permission to pollute the user's namespace. It's like knocking on someone's door and asking if you can have a beer rather than barging in and rummaging through their fridge for a beer.
Note how I use sprintf to handle the replaceable parameters. This again removes the need for eval.
I also prefer to use #! /usr/bin/env perl on my program header since it's more compatible with things like Perlbrew. You're using /usr/bin/env to find the executable Perl program that's in the user's path. This way, you don't have to know whether it's /bin/perl, /usr/bin/perl, /usr/local/bin/perl, or $HOME/perl5/perlbrew/perls/perl-5.18.0/bin/perl
To use your module, I would do this:
#! /usr/bin/env perl
use strict;
use warnings;
use feature qw(say);
use Modules::TextStuff qw(get_text);
say get_text('tmp1','jim');
Pretty much the same call you made. This prints out:
This is a template text
by jim.

Difference between a BLOCK and a function in terms of scoping in Perl

Guys I'm a little bit confused, I was playing with scoping in Perl, when i encountered this one:
#! usr/bin/perl
use warnings;
use strict;
sub nested {
our $x = "nested!";
}
print $x; # Error "Variable "$x" is not imported at nested line 10."
print our $x; # Doesn't print "nested!"
print our($x) # Doesn't print "nested!"
But when i do this:
{
our $x = "nested";
}
print our($x); # Prints "nested"
print our $x; # Prints "nested"
print $x; # Prints "nested"
So guys can you explain to me why those works and not?
To restate DVK's answer, our is just a handy aliasing tool. Every variable you use in these examples is actually named $main::x. Within any lexical scope you can use our to make an alias to that variable, with a shortened name, in that same scope; the variable doesn't reset or get removed outside, only the alias. This is unlike the my keyword which makes a new variable bound to that lexical scope.
To explain why the block example works the way it does, let's look at our explanation from "Modern Perl" book, chapter 5
Our Scope
Within given scope, declare an alias to a package variable with the our builtin.
The fully-qualified name is available everywhere, but the lexical alias is visible only within its scope.
This explains why the first two prints of your second example work (our is re-declared in print's scope), whereas the third one does not (as our only aliases $x to the package variable within the block's scope). Please note that printing $main::x will work correctly - it's only the alias that is scoped to the block, not the package variable itself.
As far as with the function:
print our $x; and print our($x) "don't work" - namely, correctly claim the value is uninitialized - since you never called the function which would initialize the variable. Observe the difference:
c:\>perl -e "use strict; use warnings; sub x { our $x = 1;} print our $x"
Use of uninitialized value $x in print at -e line 1.
c:\>perl -e "use strict; use warnings; sub x { our $x = 1;} x(); print our $x"
1
print $x; won't work for the same reason as with the block - our only scopes the alias to the block (i.e. in this case body of the sub) therefore you MUST either re-alias it in the main block's scope (as per print our $x example), OR use fully qualified package global outside the sub, in which case it will behave as expected:
c:\>perl -e "use strict; use warnings; sub x { our $x = 1;} print $main::x"
Use of uninitialized value $x in print at -e line 1.
c:\>perl -e "sub x { our $x = 1;} x(); print $main::x"
1