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
In Perl 5.26.1 I get:
Experimental values on scalar is now forbidden at /funcx.pm line 110.
Where line 110 is the foreach in
sub checkSsh {
foreach my $slave (values $::c{slaves}) {
...
}
}
$c contains
$VAR1 = {
'slaves' => {
'48' => '10.10.10.48'
},
};
where
our %c = %{YAML::Syck::LoadFile($config)};
Question
What is actually the problem? And how should it be fixed?
Perl is complaining that you are calling the values builtin on a SCALAR, in this case a HASHREF:
Properly de-referencing your slaves key allows values to work as expected:
foreach my $slave ( values %{ $c{slaves} } ) {
...
}
As to the specific warning you receive, they address that directly in the perldoc page:
Starting with Perl 5.14, an experimental feature allowed values to
take a scalar expression. This experiment has been deemed
unsuccessful, and was removed as of Perl 5.24.
To avoid confusing would-be users of your code who are running earlier
versions of Perl with mysterious syntax errors, put this sort of thing
at the top of your file to signal that your code will work only on
Perls of a recent vintage:
use 5.012; # so keys/values/each work on arrays
The following code does not print the 'HASH' type. What is wrong with this code ?
#! /usr/bin/perl
$prices{'pizza'} = 12.00;
$prices{'coke'} = 1.25;
$prices{'sandwich'} = 3.00;
print ref($prices);
First of all, you should put use strict; and use warnings; at the top of your script (and do that for all the future Perl code as well). After doing so, you will see the following:
Global symbol "%prices" requires explicit package name at ./a.pl line 4.
Global symbol "%prices" requires explicit package name at ./a.pl line 5.
Global symbol "%prices" requires explicit package name at ./a.pl line 6.
Global symbol "$prices" requires explicit package name at ./a.pl line 7.
Execution of ./a.pl aborted due to compilation errors.
What it means is that you tried to use to separate variables: a %prices hash and a $prices scalar.
After fixing variable declaration using my %prices;, you can get a reference to your %prices hash as follows:
my $prices_ref = \%prices;
print ref($prices_ref);
From formal standpoint, the answer may be shorter:
ref($prices) would return 1 if $prices value were a reference to another variable or false otherwise.
ref($prices) is the first use of an undeclared variable $prices (previous lines refer to another undeclared variable - hash %prices).
The value of $prices is undef and ref($prices) is an empty string.
Probably, your idea was to write
$prices->{'pizza'} = 12.00;
$prices->{'coke'} = 1.25;
$prices->{'sandwich'} = 3.00;
print ref($prices);
(edit) TL;DR: my problem was that I though the Win32 API defines were true integer constants (as in the platform SDK headers) while the Win32 Perl wrapper defines them as subs. Thus caused the one-liner parsing misunderstood.
While testing in a one-liner a call to Win32::MsgBox, I am puzzled by the following : giving that the possible arguments for MsgBox are the message, a sum of flags to chose the kind of buttons (value 0..5) and message box icon "constants" (MB_ICONSTOP, ...) and the title
calling perl -MWin32 -e"Win32::MsgBox world, 4+MB_ICONQUESTION, hello" gives the expected result
while the looking similar code perl -MWin32 -e"Win32::MsgBox world, MB_ICONQUESTION+4, hello" is wrong
I first though that it comes from my lack of parenthesis, but adding some perl -MWin32 -e"Win32::MsgBox (world, MB_ICONQUESTION+4, hello)" gives exactly the same wrong result.
I tried with a colleague to dig deeper and display the parameters that are passed to a function call (as the MB_xxx constants are actually subs) with the following code
>perl -Mstrict -w -e"sub T{print $/,'called T(#'.join(',',#_).'#)'; 42 }; print $/,'results:', join ' ,', T(1), T+1, 1+T"
that outputs
called T(#1#)
called T(##)
called T(#1,43#)
results:42 ,42
but I can't understand why in the list passed to join() the args T+1, 1+T are parsed as T(1, 43)...
B::Deparse to the rescue:
C:>perl -MO=Deparse -MWin32 -e"Win32::MsgBox world, MB_ICONQUETION+4, hello"
use Win32;
Win32::MsgBox('world', MB_ICONQUESTION(4, 'hello'));
-e syntax OK
C:>perl -MO=Deparse -MWin32 -e"Win32::MsgBox world, 4+MB_ICONQESTION, hello"
use Win32;
Win32::MsgBox('world', 4 + MB_ICONQUESTION(), 'hello');
-e syntax OK
The MB_ICONQUESTION call in the first case is considered a function call with the arguments +4, 'hello'. In the second case, it is considered as a function call with no arguments, and having 4 added to it. It is not a constant, it seems, but a function.
In the source code we get this verified:
sub MB_ICONQUESTION { 0x00000020 }
It is a function that returns 32 (00100000 in binary, indicating a bit being set). Also as Sobrique points out, this is a flag variable, so you should not use addition, but the bitwise logical and/or operators.
In your case, it just accepts any arguments and ignores them. This is a bit confusing if you are expecting a constant.
In your experiment case, the statement
print $/,'results:', join ' ,', T(1), T+1, 1+T
Is interpreted
print $/,'results:', join ' ,', T(1), T(+1, (1+T))
Because execution from right to left goes
1+T = 43
T +1, 43 = 42
T(1) = 42
Because plus + has higher precedence than comma ,, and unary + even higher.
To disambiguate, you need to do use parentheses to clarify precedence:
print $/,'results:', join ' ,', T(1), T()+1, 1+T
# ^^-- parentheses
As a general rule, one should always use parentheses with subroutine calls. In perldoc perlsub there are 4 calling notations:
NAME(LIST); # & is optional with parentheses.
NAME LIST; # Parentheses optional if predeclared/imported.
&NAME(LIST); # Circumvent prototypes.
&NAME; # Makes current #_ visible to called subroutine.
Of which in my opinion, only the first one is transparent, and the other ones a bit obscure.
This is all to do with how you're invoking T and how perl is interpreting the results.
If we deparse your example we get:
BEGIN { $^W = 1; }
sub T {
use strict;
print $/, 'called T(#' . join(',', #_) . '#)';
42;
}
use strict;
print $/, 'results:', join(' ,', T(1), T(1, 1 + T()));
This is clearly not what you've got in mind, but does explain why you get the result you do.
I would suggest in your original example - rather that + you may wish to consider using | as it looks very much like MB_ICONQUESTION is intended to be a flag.
So:
use strict;
use warnings;
use Win32 qw( MB_ICONQUESTION );
print MB_ICONQUESTION;
Win32::MsgBox( "world", 4 | MB_ICONQUESTION , "hello" );
Or
use strict;
use warnings;
use Win32 qw( MB_ICONQUESTION );
print MB_ICONQUESTION;
Win32::MsgBox( "world", MB_ICONQUESTION | 4 , "hello" );
Produce the same result.
This is because of precence when invoking subroutines without brackets - you can do:
print "one", "two";
And both are treated as arguments to print. Perl assumes that arguments after a sub are to be passed to it.
+4 is enumerated as an argument, and passed to T.
sub test { print #_,"\n";};
test 1;
test +1;
If we deparse this, we see perl treats it as:
test 1;
test 1;
So ultimately - there is a bug in Win32 that you have found, that would be fixable by:
sub MB_ICONQUESTION() {0x00000020}
Win32::MsgBox "world", 4 + MB_ICONQUESTION, "hello";
Win32::MsgBox "world", MB_ICONQUESTION + 4, "hello";
Or perhaps:
use constant MB_ICONQUESTION => 0x00000020;
Or as noted - the workaround in your code - don't use + and instead use | which is going to have the same result for bit flag operations, but because of operator precedence is never going to be passed into the subroutine. (Or of course, always specify the parenthesis for your constants)
$a++; # ok
$a--; # ok
--$a; # ok
++$a; # ok
--$a++; # syntax error
$a++--; # syntax error
($a++)--; # syntax error
--$a--; # syntax error
On some of these, I can sort of see why- but on like --$a-- there is no ambiguity and no precedence conflict. I'm floored Larry didn't let me do that.. (and don't even get me started on the lack of a floor operator!)
Not that I would need or want to- I was just trying to understand more about how these operators worked and discovered that sort of surprising result..
In the Perldoc for auto increment/decrement we find:
"++" and "--" work as in C.
and slightly earlier on the same page
Perl operators have the following associativity and precedence, listed from highest precedence to lowest. Operators borrowed from C keep the same precedence relationship with each other, even where C's precedence is slightly screwy. (This makes learning Perl easier for C folks.)
Since C returns an rvalue in both cases, Perl does the same. Interestingly, C++ returns a reference to an lvalue for pre-increment/decrement thus having different semantics.
Consider the following:
length($x) = 123;
Just like ++(++$a), there is no ambiguity, there is no precedence conflict, and it would require absolutely no code to function. The limitation is completely artificial[1], which means code was added specifically to forbid it!
So why is length($x) = 123; disallowed? Because disallowing it allows us to catch errors with little or no downside.
length($x) = 123; # XXX Did you mean "length($x) == 123"?
How is it disallowed? Using a concept of lvalues. lvalues are values that are allowed to appear on the left of a scalar assignment.
Some operators are deemed to return lvalues.
$x = 123; # $x returns an lvalue
$#a = 123; # $#a returns an lvalue
substr($s,0,0) = "abc"; # substr returns an lvalue
Some arguments are expected to be an lvalue.
length($x) = 123; # XXX LHS of scalar assignment must be an lvalue
++length($x); # XXX Operand of pre/post-inc/dec must be an lvalue.
The pre/post-increment/decrement operators aren't flagged as returning an lvalue. Operators that except an lvalue will not accept them.
++$a = 123; # XXX Did you mean "++$a == 123"?
This has the side effect of also preventing ++(++$a) which would work fine without the lvalue check.
$ perl -E' ++( ++$a); say $a;'
Can't modify preincrement (++) in preincrement (++) at -e line 1, near ");"
Execution of -e aborted due to compilation errors.
$ perl -E'sub lvalue :lvalue { $_[0] } ++lvalue(++$a); say $a;'
2
Changing ++$a to return an lvalue would allow ++(++$a) to work, but it would also allow ++$a = 123 to work. What's more likely? ++$a = 123 was intentional, or ++$a = 123 is a typo for ++$a == 123?
The following shows that length($x) = 123 would work without the lvalue syntax check.
$ perl -E' say length($x) = 123;'
Can't modify length in scalar assignment at -e line 1, near "123;"
Execution of -e aborted due to compilation errors.
$ perl -E'sub lvalue :lvalue { $_[0] } say lvalue(length($x)) = 123;'
123
The value you see printed is the value of the scalar returned by length after it was changed by the assignment.
For example, what do you expect for:
$a = 1;
$b = --$a++; # imaginary syntax
I think it will be harder to explain that $b is equals to 0 and $a is 1, isn't it?... In any case, I donĀ“t remember any real example where that syntax would be useful. It's useless and ugly