hashref check using if condition returns null - perl

Been using perl for a while but quite often encounter this, Say, $results is a hashref and code is like below:
$results->{'Key_1'} = 'Valid_string';
if ( $results->{'Key_1'} ) { ---> this doesn't return true
Code to do something .....
}
If my question is clear, Can anyone explain, why this happens?

The only reason I guess is that $results is not a HASH reference or your "valid string" is in fact an integer : 0
You can test it with :
print ref $results;
It should return
HASH(0x.......)
if not, there's a problem.
Better test like this to avoid any surprise :
if (exists($results->{'Key_1'})) {
# ...
}
See perldoc perlreftut
And perldoc -f exists :
exists EXPR
Given an expression that specifies an element of a hash, returns true if the specified element in the hash has ever been initialized, even if the corresponding value is undefined.

That's not going to happen for that string. That could be true for other strings.
$results->{'Key_1'} = ''; # Empty string is false.
$results->{'Key_1'} = '0'; # Zero is false.
Or maybe you didn't assign a string at all
$results->{'Key_1'} = 0; # Zero is false.
$results->{'Key_1'} = undef; # Undef is false.
defined will return true for the empty string and zero:
if ( defined( $results->{'Key_1'} ) ) {
exists will return true for the empty string, zero and undef:
if ( exists( $results->{'Key_1'} ) ) {

Related

print result of comparison operators [duplicate]

I have tried:
$var = false;
$var = FALSE;
$var = False;
None of these work. I get the error message
Bareword "false" not allowed while "strict subs" is in use.
In Perl, the following evaluate to false in conditionals:
0
'0'
undef
'' # Empty scalar
() # Empty list
('')
The rest are true. There are no barewords for true or false.
Since 5.36, you can use true and false from the builtin module/namespace. These are special true and false values that can be identified using is_bool. This is an experimental feature at this time.
But while these could be said to return the true and false, they are are but a true or false value respectively. In fact, every scalar is either true or false.
The most complete, concise definition of a false value I've come across is:
Anything that stringifies to the empty string or the string 0 is false. Everything else is true.
Therefore, the following values are false:
false (5.36+)
The empty string
Numerical value zero
An undefined value
An object with an overloaded boolean operator that evaluates one of the above.
A magical variable that evaluates to one of the above on fetch.
Any other scalar is true.
Keep in mind that an empty list literal (()) evaluates to an undefined value in scalar context, so it evaluates to something false.
A note on "true zeroes"
While numbers that stringify to 0 are false, strings that numify to zero aren't necessarily. The only false strings are 0 and the empty string. Any other string, even if it numifies to zero, is true.
The following are strings that are true as a boolean and zero as a number:
Without a warning:
"0.0"
"0E0"
"00"
"+0"
"-0"
" 0"
"0\n"
".0"
"0."
"0 but true"
"\t00"
"\n0e1"
"+0.e-9"
With a warning:
Any string for which Scalar::Util::looks_like_number returns false. (e.g. "abc")
Perl doesn't have a native boolean type, but you can use comparison of integers or strings in order to get the same behavior. Alan's example is a nice way of doing that using comparison of integers. Here's an example
my $boolean = 0;
if ( $boolean ) {
print "$boolean evaluates to true\n";
} else {
print "$boolean evaluates to false\n";
}
One thing that I've done in some of my programs is added the same behavior using a constant:
#!/usr/bin/perl
use strict;
use warnings;
use constant false => 0;
use constant true => 1;
my $val1 = true;
my $val2 = false;
print $val1, " && ", $val2;
if ( $val1 && $val2 ) {
print " evaluates to true.\n";
} else {
print " evaluates to false.\n";
}
print $val1, " || ", $val2;
if ( $val1 || $val2 ) {
print " evaluates to true.\n";
} else {
print " evaluates to false.\n";
}
The lines marked in "use constant" define a constant named true that always evaluates to 1, and a constant named false that always evaluates by 0. Because of the way that constants are defined in Perl, the following lines of code fails as well:
true = 0;
true = false;
The error message should say something like "Can't modify constant in scalar assignment."
I saw that in one of the comments you asked about comparing strings. You should know that because Perl combines strings and numeric types in scalar variables, you have different syntax for comparing strings and numbers:
my $var1 = "5.0";
my $var2 = "5";
print "using operator eq\n";
if ( $var1 eq $var2 ) {
print "$var1 and $var2 are equal!\n";
} else {
print "$var1 and $var2 are not equal!\n";
}
print "using operator ==\n";
if ( $var1 == $var2 ) {
print "$var1 and $var2 are equal!\n";
} else {
print "$var1 and $var2 are not equal!\n";
}
The difference between these operators is a very common source of confusion in Perl.
I recommend use boolean;. You have to install the boolean module from cpan though.
My favourites have always been
use constant FALSE => 1==0;
use constant TRUE => not FALSE;
which is completely independent from the internal representation.
I came across a tutorial which have a well explaination about What values are true and false in Perl. It state that:
Following scalar values are considered false:
undef - the undefined value
0 the number 0, even if you write it as 000 or 0.0
'' the empty string.
'0' the string that contains a single 0 digit.
All other scalar values, including the following are true:
1 any non-0 number
' ' the string with a space in it
'00' two or more 0 characters in a string
"0\n" a 0 followed by a newline
'true'
'false' yes, even the string 'false' evaluates to true.
There is another good tutorial which explain about Perl true and false.
Beautiful explanation given by bobf for Boolean values : True or False? A Quick Reference Guide
Truth tests for different values
Result of the expression when $var is:
Expression | 1 | '0.0' | a string | 0 | empty str | undef
--------------------+--------+--------+----------+-------+-----------+-------
if( $var ) | true | true | true | false | false | false
if( defined $var ) | true | true | true | true | true | false
if( $var eq '' ) | false | false | false | false | true | true
if( $var == 0 ) | false | true | true | true | true | true
use the following file prefix, this will add to your perl script eTRUE and eFALSE, it will actually be REAL(!) true and false (just like java)
#!/usr/bin/perl
use strict;
use warnings;
use constant { #real true false, compatible with encode_json decode_json for later (we don't want field:false... will be field:0...)
eTRUE => bless( do{\(my $o = 1)}, 'JSON::PP::Boolean' ),
eFALSE => bless( do{\(my $o = 0)}, 'JSON::PP::Boolean' )
};
There are, actually, few reasons why you should use that.
My reason is that working with JSON, I've got 0 and 1 as values to keys, but this hack will make sure correct values are kept along your script.
Booleans in Raku (the programming language formerly known as Perl_6):
~$ raku
Welcome to 𝐑𝐚𝐤𝐮𝐝𝐨™ v2021.06.
Implementing the 𝐑𝐚𝐤𝐮™ programming language v6.d.
Built on MoarVM version 2021.06.
To exit type 'exit' or '^D'
> my $var = False;
False
> say $var;
False
> say $var.^name
Bool
> say $var.WHAT
(Bool)
> say ++$var
True
> say --$var
False
> say $var.Int
0
> say $var.Int + 1
1
> say ($var.Int + 1).Bool
True
> say $var.Int - 1
-1
> say ($var.Int - 1).Bool
True
> say $var.succ
True
> say $var.Int.succ
1
> say $var.pred
False
> say $var.Int.pred
-1
> say ++($var.Int); #ERROR
Cannot resolve caller prefix:<++>(Int:D); the following candidates
match the type but require mutable arguments:
(Mu:D $a is rw)
(Int:D $a is rw --> Int:D)
#<SNIP>
> say --($var.Int); #ERROR
Cannot resolve caller prefix:<-->(Int:D); the following candidates
match the type but require mutable arguments:
(Mu:D $a is rw)
(Int:D $a is rw --> Int:D)
#<SNIP>
> exit
https://docs.raku.org/type/Bool
https://docs.raku.org/language/syntax#index-entry-Boolean_(literals)

If statement with scalar conditional

I am having difficulty understanding the following expression in Perl.
for (my $attempts = 0; $attempts < $maxatt; $attempts++) {
print "Please try again.\n" if $attempts;
print "$prompt: ";
$response = readline(*STDIN);
chomp($response);
return $response if $response;
}
What does it mean to use a scalar as a conditional? I.e. what makes it return true vs false? I am assuming the statement reads if ($attempts) { print ... }.
Perl doesn't have a distinct concept of "Boolean value".
Per the perldata manpage:
A scalar value is interpreted as FALSE in the Boolean sense if it is undefined, the null string or the number 0 (or its string equivalent, "0"), and TRUE if it is anything else. The Boolean context is just a special kind of scalar context where no conversion to a string or a number is ever performed.
So in your example, if $attempts means if $attempts > 0.
Incidentally, this also means that something like $attempts > 0 does not evaluate to a Boolean, because there's no such thing. Instead, per the perlop manpage, operators like >:
[…] return 1 for true and a special version of the defined empty string, "", which counts as a zero but is exempt from warnings about improper numeric conversions, just as "0 but true" is.
(Hat-tip to ikegami for pointing out that what they return for FALSE is not quite the normal empty string.)

can any one explain me behaviour of the perl program

$a="";
$b="n";
$c = !$a;
$d = !$b;
print $c , "\n" , $d;
if($d == 0){
print "zero";
}
I wrote this perl program i expected the output to be as follows
1
0Zero
but it prints
1
zero
can any one explain me why is it like that??
Variables in Perl are treated as either numbers or strings depending on the context. If you haven't treated something as a number when assigning to it, Perl will treat it like a string when you print it.
Because of this, false values are a bit different in Perl than in languages with stronger typing (emphasis added by me):
The number 0, the strings '0' and "" , the empty list () , and undef
are all false in a boolean context. All other values are true.
Negation of a true value by ! or not returns a special false value.
When evaluated as a string it is treated as "" , but as a number, it
is treated as 0. Most Perl operators that return true or false behave
this way.
So, the issue here is that ! is a logical operator rather than an arithmetic one. Therefore, it returns a logically false value, which is represented in different ways depending on the context.
If you want to make sure something is treated as a number, you have a few options. You can perform an arithmetic operation, which will make Perl consider the result a number:
$d=!$b+0;
print $d;
You can use sprintf or printf to explicitly control the display:
printf '%d', $d;
Or you can use int:
print int $d;
(Note: this all may seem a bit complicated. But it was designed so that the language will just do what you want, and you won't have to think about it. And normally it does. There are only occasional edge cases where you need to do something other than Perl's default behavior.)
In perlsyn, under Truth and Falsehood you read
The number 0, the strings '0' and "" , the empty list () , and undef are all false in a boolean context. All other values are true. Negation of a true value by ! or not returns a special false value. When evaluated as a string it is treated as "" , but as a number, it is treated as 0. Most Perl operators that return true or false behave this way.
This is what you experience. $a is false value, so !$a, assigned to $c, becomes a true value, accordingly printed as 1. $b is a true value, so !$b, assigned to $d, becomes that special false value. In the print statement (print $c , "\n" , $d;), it is evaluated in string context, so the empty string is printed. The if statement ($d == 0) evaluates it in number context, so it is a 0, hence zero is printed.
!$b evaluates to empty string '', as false values are not represented by zero when stringified by print(), "$bool", or some other string operation.
$a="";
$b="n";
$c = !$a;
$d = !$b;
print $c , "\n" , $d;
if($d == 0){
print "zero";
}
use Data::Dumper;
print Dumper {
'$a' => $a,
'$b' => $b,
'$c' => $c,
'$d' => $d,
'$d == 0' => $d == 0,
};
output
$VAR1 = {
'$d == 0' => 1, # boolean true
'$b' => 'n',
'$d' => '', # boolean false
'$c' => 1,
'$a' => ''
};
Perl operators such as ! that return boolean values return a special value for false: it is "" when used in string context and 0 when used in numeric context.
So when you print it, it is "", not "0". But if you try to use it as a number, it doesn't give a warning the way "" does. Compare:
perl -wle'$false = !1; print "string: ", $false, " number: ", 0+$false'
string: number: 0
and
perl -wle'$empty = ""; print "string: ", $empty, " number: ", 0+$empty'
Argument "" isn't numeric in addition (+) at -e line 1.
string: number: 0

When to use defined

I am a little confused as which way to test parameters. Here are two examples from source code posted below. First is this
if(!defined($DBHdl) || !defined($acct_no));
the way to test for undefined parameters?
Second, after assigning to a hashref
$ptMtrRecRef = $ptSelHdl->fetchrow_hashref;
is the best way to test for $ptMtrRecRef being defined to use
if(!$ptMtrRecRef)
or
if(!defined($ptMtrRecRef))?
###############################################################################
# Returns count of meters per account number.
# $PkNam -- package name discarded
# $DBHdl -- ICS database handle
# $acct_no -- water account number
sub mgbl_get_meter_count
{
my ($PkNam, $DBHdl, $acct_no) = #_;
die("mgbl_get_meter_count passed undef handles.\n")
if(!defined($DBHdl) || !defined($acct_no));
my $ptSelHdl;
my $ptMtrRecRef;
my $sql_statement =
"select count(*) from meter m where m.acct_no = ".$acct_no.";";
$ptSelHdl = $DBHdl->prepare($sql_statement);
die("Cannot prepare select count(*) from meter m\n")
if(!$ptSelHdl || !$ptSelHdl->execute);
$ptMtrRecRef = $ptSelHdl->fetchrow_hashref;
return $ptMtrRecRef;
}
$sth->fetchrow_hashref will either return undef or a reference to a hash. As such
if (defined($row))
and
if ($row)
are equivalent here. (undef is false, and reference is always true.) I opt for the simpler alternative.
Same idea for $dbh->prepare.
In the case of the code you posted, I would also do as ikegami said, and use the shorter form.
There are occasions when that isn't suitable, however, for example if a variable could have a legitimate value that would be treated as false if simply used in a true/false test. For example:
my $value = 0;
print "defined\n" if defined $value; # prints 'defined'
print "true\n" if $value; # does not print anything
Well , in perl script language, defined($a) is just a sub routine to test if $a is "undef",nothing else. So ,you will ask ,what is undef?
To be accurate, it is a perl subroutine ,the same as defined.But when it has no parameter, it can be considered as a perl-special scalar . For example , when you pop a value from an empty array ,it will return an undef.When you call subroutine "undef $b",then $b will become undef($b must be an left value),nothing else. Only in this case, defined($b) will return false.But if $c is an empty string like "" ,number zero ,or string "0" ,defined($c) will still return true;
But if you use a simple boolean expression instead of defined,it becomes totally different. A simple Boolean test will not distinguish among undef, zero, the empty string, and "0" .So , it absolutely depends on your pratical requirement when determining using defined() or just a boolean test.

How do I use boolean variables in Perl?

I have tried:
$var = false;
$var = FALSE;
$var = False;
None of these work. I get the error message
Bareword "false" not allowed while "strict subs" is in use.
In Perl, the following evaluate to false in conditionals:
0
'0'
undef
'' # Empty scalar
() # Empty list
('')
The rest are true. There are no barewords for true or false.
Since 5.36, you can use true and false from the builtin module/namespace. These are special true and false values that can be identified using is_bool. This is an experimental feature at this time.
But while these could be said to return the true and false, they are are but a true or false value respectively. In fact, every scalar is either true or false.
The most complete, concise definition of a false value I've come across is:
Anything that stringifies to the empty string or the string 0 is false. Everything else is true.
Therefore, the following values are false:
false (5.36+)
The empty string
Numerical value zero
An undefined value
An object with an overloaded boolean operator that evaluates one of the above.
A magical variable that evaluates to one of the above on fetch.
Any other scalar is true.
Keep in mind that an empty list literal (()) evaluates to an undefined value in scalar context, so it evaluates to something false.
A note on "true zeroes"
While numbers that stringify to 0 are false, strings that numify to zero aren't necessarily. The only false strings are 0 and the empty string. Any other string, even if it numifies to zero, is true.
The following are strings that are true as a boolean and zero as a number:
Without a warning:
"0.0"
"0E0"
"00"
"+0"
"-0"
" 0"
"0\n"
".0"
"0."
"0 but true"
"\t00"
"\n0e1"
"+0.e-9"
With a warning:
Any string for which Scalar::Util::looks_like_number returns false. (e.g. "abc")
Perl doesn't have a native boolean type, but you can use comparison of integers or strings in order to get the same behavior. Alan's example is a nice way of doing that using comparison of integers. Here's an example
my $boolean = 0;
if ( $boolean ) {
print "$boolean evaluates to true\n";
} else {
print "$boolean evaluates to false\n";
}
One thing that I've done in some of my programs is added the same behavior using a constant:
#!/usr/bin/perl
use strict;
use warnings;
use constant false => 0;
use constant true => 1;
my $val1 = true;
my $val2 = false;
print $val1, " && ", $val2;
if ( $val1 && $val2 ) {
print " evaluates to true.\n";
} else {
print " evaluates to false.\n";
}
print $val1, " || ", $val2;
if ( $val1 || $val2 ) {
print " evaluates to true.\n";
} else {
print " evaluates to false.\n";
}
The lines marked in "use constant" define a constant named true that always evaluates to 1, and a constant named false that always evaluates by 0. Because of the way that constants are defined in Perl, the following lines of code fails as well:
true = 0;
true = false;
The error message should say something like "Can't modify constant in scalar assignment."
I saw that in one of the comments you asked about comparing strings. You should know that because Perl combines strings and numeric types in scalar variables, you have different syntax for comparing strings and numbers:
my $var1 = "5.0";
my $var2 = "5";
print "using operator eq\n";
if ( $var1 eq $var2 ) {
print "$var1 and $var2 are equal!\n";
} else {
print "$var1 and $var2 are not equal!\n";
}
print "using operator ==\n";
if ( $var1 == $var2 ) {
print "$var1 and $var2 are equal!\n";
} else {
print "$var1 and $var2 are not equal!\n";
}
The difference between these operators is a very common source of confusion in Perl.
I recommend use boolean;. You have to install the boolean module from cpan though.
My favourites have always been
use constant FALSE => 1==0;
use constant TRUE => not FALSE;
which is completely independent from the internal representation.
I came across a tutorial which have a well explaination about What values are true and false in Perl. It state that:
Following scalar values are considered false:
undef - the undefined value
0 the number 0, even if you write it as 000 or 0.0
'' the empty string.
'0' the string that contains a single 0 digit.
All other scalar values, including the following are true:
1 any non-0 number
' ' the string with a space in it
'00' two or more 0 characters in a string
"0\n" a 0 followed by a newline
'true'
'false' yes, even the string 'false' evaluates to true.
There is another good tutorial which explain about Perl true and false.
Beautiful explanation given by bobf for Boolean values : True or False? A Quick Reference Guide
Truth tests for different values
Result of the expression when $var is:
Expression | 1 | '0.0' | a string | 0 | empty str | undef
--------------------+--------+--------+----------+-------+-----------+-------
if( $var ) | true | true | true | false | false | false
if( defined $var ) | true | true | true | true | true | false
if( $var eq '' ) | false | false | false | false | true | true
if( $var == 0 ) | false | true | true | true | true | true
use the following file prefix, this will add to your perl script eTRUE and eFALSE, it will actually be REAL(!) true and false (just like java)
#!/usr/bin/perl
use strict;
use warnings;
use constant { #real true false, compatible with encode_json decode_json for later (we don't want field:false... will be field:0...)
eTRUE => bless( do{\(my $o = 1)}, 'JSON::PP::Boolean' ),
eFALSE => bless( do{\(my $o = 0)}, 'JSON::PP::Boolean' )
};
There are, actually, few reasons why you should use that.
My reason is that working with JSON, I've got 0 and 1 as values to keys, but this hack will make sure correct values are kept along your script.
Booleans in Raku (the programming language formerly known as Perl_6):
~$ raku
Welcome to 𝐑𝐚𝐤𝐮𝐝𝐨™ v2021.06.
Implementing the 𝐑𝐚𝐤𝐮™ programming language v6.d.
Built on MoarVM version 2021.06.
To exit type 'exit' or '^D'
> my $var = False;
False
> say $var;
False
> say $var.^name
Bool
> say $var.WHAT
(Bool)
> say ++$var
True
> say --$var
False
> say $var.Int
0
> say $var.Int + 1
1
> say ($var.Int + 1).Bool
True
> say $var.Int - 1
-1
> say ($var.Int - 1).Bool
True
> say $var.succ
True
> say $var.Int.succ
1
> say $var.pred
False
> say $var.Int.pred
-1
> say ++($var.Int); #ERROR
Cannot resolve caller prefix:<++>(Int:D); the following candidates
match the type but require mutable arguments:
(Mu:D $a is rw)
(Int:D $a is rw --> Int:D)
#<SNIP>
> say --($var.Int); #ERROR
Cannot resolve caller prefix:<-->(Int:D); the following candidates
match the type but require mutable arguments:
(Mu:D $a is rw)
(Int:D $a is rw --> Int:D)
#<SNIP>
> exit
https://docs.raku.org/type/Bool
https://docs.raku.org/language/syntax#index-entry-Boolean_(literals)