How to fix "Experimental values on scalar is now forbidden" - perl

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

Related

Printing hash value in Perl

When I print a variable, I am getting a HASH(0xd1007d0) value. I need to print the values of all the keys and values. However, I am unable to as the control does not enter the loop.
foreach my $var(keys %{$HashVariable}){
print"In the loop \n";
print"$var and $HashVariable{$var}\n";
}
But the control is not even entering the loop. I am new to perl.
I can't answer completely, because it depends entirely on what's in $HashVariable.
The easiest way to tell what's in there is:
use Data::Dumper;
print Dumper $HashVariable;
Assuming this is a hash reference - which it would be, if print $HashVariable gives HASH(0xdeadbeef) as an output.
So this should work:
#!/usr/bin/env perl
use strict;
use warnings;
my $HashVariable = { somekey => 'somevalue' };
foreach my $key ( keys %$HashVariable ) {
print $key, " => ", $HashVariable->{$key},"\n";
}
The only mistake you're making is that $HashVariable{$key} won't work - you need to dereference, because as it stands it refers to %HashVariable not $HashVariable which are two completely different things.
Otherwise - if it's not entering the loop - it may mean that keys %$HashVariable isn't returning anything. Which is why that Dumper test would be useful - is there any chance you're either not populating it correctly, or you're writing to %HashVariable instead.
E.g.:
my %HashVariable;
$HashVariable{'test'} = "foo";
There's an obvious problem here, but it wouldn't cause the behaviour that you are seeing.
You think that you have a hash reference in $HashVariable and that sounds correct given the HASH(0xd1007d0) output that you see when you print it.
But setting up a hash reference and running your code, gives slightly strange results:
my $HashVariable = {
foo => 1,
bar => 2,
baz => 3,
};
foreach my $var(keys %{$HashVariable}){
print"In the loop \n";
print"$var and $HashVariable{$var}\n";
}
The output I get is:
In the loop
baz and
In the loop
bar and
In the loop
foo and
Notice that the values aren't being printed out. That's because of the problem I mentioned above. Adding use strict to the program (which you should always do) tells us what the problem is.
Global symbol "%HashVariable" requires explicit package name (did you forget to declare "my %HashVariable"?) at hash line 14.
Execution of hash aborted due to compilation errors.
You are using $HashVariable{$var} to look up a key in your hash. That would be correct if you had a hash called %HashVariable, but you don't - you have a hash reference called $HashVariable (note the $ instead of %). To look up a key from a hash reference, you need to use a dereferencing arrow - $HashVariable->{$var}.
Fixing that, your program works as expected.
use strict;
use warnings;
my $HashVariable = {
foo => 1,
bar => 2,
baz => 3,
};
foreach my $var(keys %{$HashVariable}){
print"In the loop \n";
print"$var and $HashVariable->{$var}\n";
}
And I see:
In the loop
bar and 2
In the loop
foo and 1
In the loop
baz and 3
The only way that you could get the results you describe (the HASH(0xd1007d0) output but no iterations of the loop) is if you have a hash reference but the hash has no keys.
So (as I said in a comment) we need to see how your hash reference is created.

Global symbol "%formsequence" requires explicit package name at line 37

I am trying to execute a Perl CGI script, but I am getting an error:
Global symbol "%formsequence" requires explicit package name at line 37.
I did some research and found that use strict forces me to declare the variables before I use them or store any data, but in my program I have declared them and that is why I don't understand the error. Here is my script:
#!/usr/bin/perl -w
use strict;
my %errors;
my %form;
my #formsequence;
my %fields = (
"lname" => "Last Name",
"phone" => "Phone",
"fname" => "Fist Name"
);
my %patterns = (
"lname" => '[A-Z][a-z]{2,50}',
"phone" => '\d{3}-\d{3}-\d{4}',
"fname" => '[A-Z][A-Za-z]{2,60}'
);
#formsequence = ("lname", "phone", "phone");
print "content-type/html\n\n";
if ($ENV{REQUEST_METHOD} eq "POST") {
&readformdata;
if (&checkrequiredfields) {
print "Form Data validated successfully!";
}
else {
foreach (keys (%fields)) {
if ($fields{$_} != $formsequence{$_}) { <-- line 37
$errors{$_}="Not in correct sequence\n";
}
}
}
I suspect you may be viewing the concept of an 'array' from the perspective of a PHP developer. In Perl a hash and an array are separate data structures.
Arrays are declared using the # prefix and you refer to elements using square brackets around an integer index:
my #names = ('Tom', 'Dick', 'Larry');
say $names[0]; # 'Tom'
say $names[-1]; # 'Larry'
my $count = #names; # $count now equals 3
foreach my $i (0..$#names) {
say $names[$i];
}
Hashes are declared using the % prefix and you refer to elements using curly braces around a string key:
my %rgb = (
red => '#ff0000',
white => '#ffffff',
blue => '#0000ff',
);
say $rgb{'red'}; # '#ff0000'
say $rgb{blue}; # '#0000ff' quotes optional around bareword keys
foreach my $k (keys %rgb) {
say $rgb{$k};
}
You wouldn't normally use the keys function on an array - in fact older versions of Perl don't even support it, newer versions will return a range of integers (e.g.: 0..2).
When you call keys on a hash the keys have no inherent order, and the order may change.
Other things worth knowing:
Using & to call a function is really old style (i.e. early 90s), these days we'd use readformdata() instead of &readformdata.
The != operator is a numeric comparison operator so only use it when the values you're comparing are actually numbers. If you want to check two strings are 'not equal' then use ne instead (e.g.: if($thing1 ne $thing2) { ... }).
This seems to be some rather old Perl.
You use -won the shebang line rather than use warnings (which has been available since Perl 5.6.0 was released in 2000.
You use a (presumably) custom readformdata() function instead of CGI,pm's params() method. CGI.pm was added to the Perl core in 1997 (it was recently removed - but that's not a reason to not use it).
You use ampersands on function calls. These haven't been necessary since Perl 5 was released in 1994.
Your problem is caused by declaring an array, #formsequence, which you then try to access as a hash - $formsequence{$_} means, "look up the key $_ in the hash %formsequence. In Perl, arrays and hashes are two completely different data types and it is possible (although not recommended for, hopefully, obvious reasons) to have an array and a hash with the same name.
You declare arrays like this - using #:
my #array = ('foo', 'bar', 'baz');
And access individual element like this - using [...]:
print $array[0]; # prints 'foo'
You declare hashes like this - using `%':
my %hash = (foo => 'Foo', bar => 'Bar', baz => 'Baz');
And access individual elements like ths - using {...}:
print $hash{foo}; # prints 'Foo'
Arrays are indexed using integers and are ordered. Hashes are indexed using strings and are unordered.
I can't really suggest a fix for your code as it's not really clear what you are trying to do. It appears that you want to check that parameters appear in a certain order, but this is doomed to failure as a) you can't guarantee the order in which CGI parameters are transmitted from the browser to your web server and b) you can't guarantee the order in which keys(%fields) will return the keys from your %fields hash.
If you explain in a little more detail what you are trying to do, then we might be able to help you more.

What is "Use of unitialized value $. in range (or flip)" trying to tell me in Perl

I have the following code snippet in Perl:
my $argsize = #args;
if ($argsize >1){
foreach my $a ($args[1..$argsize-1]) {
$a =~ s/(.*[-+*].*)/\($1\)/; # if there's a math operator, put in parens
}
}
On execution I'm getting "Use of unitialized value $. in range (or flip) , followed by Argument "" isn't numeric in array element at... both pointing to the foreach line.
Can someone help me decipher the error message (and fix the problem(s))? I have an array #args of strings. The code should loop through the second to n't elements (if any exist), and surround individual args with () if they contain a +,-, or *.
I don't think the error stems from the values in args, I think I'm screwing up the range somehow... but I'm failing when args has > 1 element. an example might be:
<"bla bla bla"> <x-1> <foo>
The long and short of it is - your foreach line is broken:
foreach my $a (#args[1..$argsize-1]) {
Works fine. It's because you're using a $ which says 'scalar value' rather than an # which says array (or list).
If you use diagnostics you get;
Use of uninitialized value $. in range (or flip) at
(W uninitialized) An undefined value was used as if it were already
defined. It was interpreted as a "" or a 0, but maybe it was a mistake.
To suppress this warning assign a defined value to your variables.
To help you figure out what was undefined, perl will try to tell you
the name of the variable (if any) that was undefined. In some cases
it cannot do this, so it also tells you what operation you used the
undefined value in. Note, however, that perl optimizes your program
and the operation displayed in the warning may not necessarily appear
literally in your program. For example, "that $foo" is usually
optimized into "that " . $foo, and the warning will refer to the
concatenation (.) operator, even though there is no . in
your program.
You can reproduce this error by:
my $x = 1..3;
Which is actually pretty much what you're doing here - you're trying to assign an array value into a scalar.
There's a load more detail in this question:
What is the Perl context with range operator?
But basically: It's treating it as a range operator, as if you were working your way through a file. You would be able to 'act on' particular lines in the file via this operator.
e.g.:
use Data::Dumper;
while (<DATA>) {
my $x = 2 .. 3;
print Dumper $x;
print if $x;
}
__DATA__
line one
another line
third line
fourth line
That range operator is testing line numbers - and because you have no line numbers (because you're not iterating a file) it errors. (But otherwise - it might work, but you'd get some really strange results ;))
But I'd suggest you're doing this quite a convoluted way, and making (potentially?) an error, in that you're starting your array at 1, not zero.
You could instead:
s/(.*[-+*].*)/\($1\)/ for #args;
Which'll have the same result.
(If you need to skip the first argument:
my ( $first_arg, #rest ) = #args;
s/(.*[-+*].*)/\($1\)/ for #rest;
But that error at runtime is the result of some of the data you're feeding in. What you've got here though:
use strict;
use warnings;
my #args = ( '<"bla bla bla">', '<x-1>', '<foo>' );
print "Before #args\n";
s/(.*[-+*].*)/\($1\)/ for #args;
print "After: #args\n";

Strange perl code - looking for explanation

I know a little bit perl, but not enough deeply to understand the next.
Reading perldelta 5.18 i found the next piece of code what is already disabled in 5.18. Not counting this, still want understand how it's works.
Here is the code and in the comments are what i understand
%_=(_,"Just another "); #initialize the %_ hash with key=>value _ => 'Just another'
$_="Perl hacker,\n"; #assign to the $_ variable with "Perl..."
s//_}->{_/e; # darkness. the /e - evauates the expression, but...
print
it prints:
Just another Perl hacker,
I tried, the perl -MO=Deparse and get the next
(%_) = ('_', 'Just another '); #initializing the %_ hash
$_ = "Perl hacker,\n"; # as above
s//%{'_';}/e; # substitute to the beginning of the $_ - WHAT?
print $_; # print the result
japh syntax OK
What is strange (at least for me) - running the "deparsed" code doesn't gives the original result and prints:
1/8Perl hacker,
I would be very happy:
if someone can explain the code, especially if someone could write an helper code, (with additional steps) what helps me understand how it is works - what happens.
explain, why the deparsed code not prints the original result.
What means the %{'_';} in the deparsed code?
The code actually executed by the substitution operator is probably actually something like
my $code = "do { $repl_expr }";
So when the replacement expression is _}->{_, the following is executed:
do { _}->{_ }
_ simply returns the string _ (since strict is off), so that's the same as
do { "_" }->{_}
which is the same as
"_"->{_}
What you have there is a hash element dereference, where the reference is a symbolic reference (i.e. a string rather than an actual reference). Normally forbidden by strict, here's an example of a symbolic reference at work:
%h1 = ( id => 123 );
%h2 = ( id => 456 );
print "h$_"->{id}, "\n"
for 1..2;
So that means
"_"->{_} # Run-time symbol lookup
is the same as
$_{_} # Compile-time symbol lookup
A similar trick is often used in one-liners.
perl -nle'$c += $_; END { print $c }'
can be shortened to
perl -nle'$c += $_; }{ print $c'
Because the code actually executed when -n is used is obtained from something equivalent to
my $code = "LINE: while (<>) { $program }";
%{'_';}
is a very weird way to write
%{'_'}
which is a hash dereference. Again, the reference here is a symbolic reference. It's equivalent to
%_
In scalar context, hash current returns a value that reports some information about that hash's internals (or a false value if empty). There's been a suggestion to change it to return the number of keys instead.

How to check if a Perl hash is defined when it doesn't have any key/value pairs

I'm trying to figure out a way to check if a hash has been declared in a Perl script while inside a module function.
Given the following script (file script.pl):
#!/usr/bin/perl -w
use strict;
use checkHash;
our %testHash = ("key"=>"value");
print &checkHash() ? 1 : 0;
Along with this module (checkHash.pm);
sub checkHash {
if(%main::testHash) {
return 1;
}
else {
return 0;
}
}
1;
Running on a Mac with OS X v10.6.7 (Snow Leopard) and Perl v5.10.0, the return value of checkHash is "1" which I would expect. However, if I remove the key value pair from the script by changing the line:
our %testHash = ("key"=>"value");
to:
our %testHash = ();
The return value is "0". My original assumption was that this would be "1", but after reading about the way the test I'm using is testing for the size in the hash, I see why that was incorrect thinking.
Is there a test that can be used in the checkHash module that will return true if the hash it's testing exists, but doesn't have any keys assigned to it?
defined() is not a meaningful test on aggregates (arrays and hashes). perldoc -f defined has this to say:
Use of "defined" on aggregates (hashes and arrays) is deprecated. It
used to report whether memory for that aggregate has ever been
allocated.
This behavior may disappear in future versions of Perl.
You should instead use a simple test for size:
if (#an_array) { print "has array elements\n" }
if (%a_hash) { print "has hash members\n" }
Testing whether a given symbol has been declared is almost certainly useless and a desire to perform it is indicative of a design problem. For the sake of completeness, however, here's tests for both lexical and dynamic symbols:
Find out if the lexical symbol $whoopee has been declared:
use Try::Tiny;
my $declared = try { use strict; $whoopee; 1 };
Find out if any dynamic symbol called FooPackage::whoopee has been declared (including hashes that spell their names %FooPackage::whoopee):
my $declared = exists $FooPackage::{whoopee};
See perldoc perldata
If you evaluate a hash in scalar context, it returns false if the hash is empty. If there are any key/value pairs, it returns true; more precisely, the value returned is a string consisting of the number of used buckets and the number of allocated buckets, separated by a slash.
That explains why your defined test seemed to work.
You can just count the keys:
sub checkHash {
return ( scalar keys %main::testHash ) ? 1 : 0;
}
perl -le 'my %h; print ( scalar keys %h ) ? 1 : 0;'
0
perl -le 'my %h = (foo=>1); print ( scalar keys %h ) ? 1 : 0;'
1