Undef value assigned to variable. - perl

The return value of 5 > 6 is undef. However when I assign the value of 5 > 6 to a variable that variable is defined. How do I pass the value of a statement using a comparison operator that resolves to undef on failure?
#!/usr/bin/perl
use strict ;
use warnings;
print'Five is more than six ? ', 5 > 6, "\n";
print 'Five is less than six ? ' , 5 < 6 , "\n";
my $wiz = 5 > 6 ;
if (defined($wiz)) {
print '$wiz is defined' ;
} else {
print '$wiz is undefined' ;
}
$ ./lessthan
Five is more than six ?
Five is less than six ? 1
$wiz is defined

How do I pass the value of a statement using a comparison operator that resolves to undef on failure?
Generally speaking, Perl doesn't promise to return any specific true or false value from its operators, and < is no exception. If you want specific values, you will need something like
$boolean ? $value_for_true : $value_for_false
so
my $wiz = 5 > 6 ? 1 : undef;
If you only care about the value you get for false, you could also use the following:
my $wiz = 5 > 6 || undef;
The two options turn out to be equivalent, but this isn't guaranteed.
The return value of 5 > 6 is undef. However when I assign the value of 5 > 6 to a variable
That's not true. The variable is assigned a defined value because 5 > 6 evaluated to a defined value. While Perl doesn't specify what false value it returns from it's operators, it usually returns the scalar sv_no, which is a dualvar that appears to be an empty string when treated as a string, and zero when treated as a number.
$ perl -wE'say "> ", "".( undef )'
Use of uninitialized value in concatenation (.) or string at -e line 1.
>
$ perl -wE'say "> ", "".( "" )'
>
$ perl -wE'say "> ", "".( 0 )'
> 0
$ perl -wE'say "> ", "".( 5>6 )'
> # Behaves as ""
$ perl -wE'say "> ", 0+( undef )'
Use of uninitialized value in addition (+) at -e line 1.
> 0
$ perl -wE'say "> ", 0+( "" )'
Argument "" isn't numeric in addition (+) at -e line 1.
> 0
$ perl -wE'say "> ", 0+( 0 )'
> 0
$ perl -wE'say "> ", 0+( 5>6 )'
> 0 # Behaves as 0

5 > 6 is not undefined, but it is a false value. In this case, a dualvar that acts like an empty string when used as a string, or 0 when used as a number.
Because the value is false, you can just do
if ( $wiz ) { ... }
If you really want $wiz to be undefined, you could do something like this.
my $wiz = 5 > 6 || undef;
Now, if the expression 5 > 6 is true, $wiz will be 1, otherwise it will be undef.

Boolean false and undef are two different things ...
comparison assignments are executed in Boolean context only returning boolean values only and undef is not boolean thing
chk this
if(defined false){
print "false is also defined thing.."
}else{
print "else .."
}
So back to question , seems like comparisons can't return undef

Related

How can a string with alpha chars in it be numerically equivalent to a number in Perl?

Is it true that Perl numerically evaluates any string that starts with a number as numerically equivalent to that number (after warning that it is not numerical)?
I am trying to understand how the various comparison operators work.
I wrote a script to output various TRUE or FALSE results as follows. (My question is posed afterward.)
(For my post I have condensed the curly braces into single lines, to save space and maybe make it easier to read.
This is my first question to StackOverflow, so if I can improve how my question was asked, or where to ask it, please let me know.)
#!/usr/bin/perl -w
#compOpers-mathyIn_TF.pl
use strict;
print "Enter expression to compare.\n";
chomp ( my $var = <STDIN> );
if ( $var == 0 ) { print "$var == 0 is TRUE.\n"; }
else { print "$var == 0 is FALSE.\n"; }
if ( $var == 1 ) { print "$var == 1 is TRUE.\n"; }
else { print "$var == 1 is FALSE.\n"; }
if ( $var eq "0" ) { print "$var eq \"0\" is TRUE.\n"; }
else { print "$var eq \"0\" is FALSE.\n"; }
if ( $var eq "1" ) { print "$var eq \"1\" is TRUE.\n"; }
else { print "$var eq \"1\" is FALSE.\n"; }
I tried this with some mathematical expressions such as "4 - 3" (and "4-3"), which didn't work. Sample output:
~\Perlscripts>perl compOpers_mathyInput_TF.pl
Enter expression to compare.
4 - 3
Argument "4 - 3" isn't numeric in numeric eq (==) at compOpers_mathyInput_TF.pl line 8, <STDIN> line 1.
4 - 3 == 0 is FALSE.
4 - 3 == 1 is FALSE.
4 - 3 eq "0" is FALSE.
4 - 3 eq "1" is FALSE.
~\Perlscripts>
After some research I realized that Perl will not mathematically parse this STDIN by default;
once I added an eval function to the code as follows (done for each if block), it worked better.
if ( eval($var) == 0 ) { print "eval($var) == 0 is TRUE\.\n"; }
else { print "eval($var) == 0 is FALSE\.\n"; }
But before getting to that point, I had already received some puzzling results with my original code.
At first I thought the below result was mathematically parsing my input of "1 x 1", but that doesn't actually seem to be the case.
~\Perlscripts>perl compOpers_mathyInput_TF.pl
Enter expression to compare.
1 x 1
Argument "1 x 1" isn't numeric in numeric eq (==) at compOpers_mathyInput_TF.pl line 8, <STDIN> line 1.
1 x 1 == 0 is FALSE.
1 x 1 == 1 is TRUE. <<<-----
1 x 1 eq "0" is FALSE.
1 x 1 eq "1" is FALSE.
~\Perlscripts>
Here are other similar results where Perl is evaluating the second truth test in the script ( == 1 ) test to be TRUE, even though they are clearly not equal (along with a couple FALSE results too):
1 x 1 == 1 is TRUE.<br>
1/235 == 1 is TRUE.<br>
1x2 == 1 is TRUE.<br>
2x1 == 1 is FALSE.<br>
1andsometimes7 == 1 is TRUE.<br>
7isnt1 == 1 is FALSE.<br>
Question 1)
From what I can see, Perl numerically evaluates any string that starts with a number as numerically equivalent to that number (after warning that it is not numerical).
Is this true? Is it a problem? Why does it work this way?
(I also tried setting the second truth test to match a different number than "1" (I used 8), and the results were the same.)
I also have a follow up question, a result that was somewhat surprising to me. Once I changed the script to use eval, the numerical comparisons worked as expected. But the string comparison also came up true here:
~\Perlscripts>perl compOpers_eval-mathyInput_TF.pl
Enter first expression to compare.
4-3
eval(4-3) == 0 is FALSE.
eval(4-3) == 1 is TRUE.
eval(4-3) eq "0" is FALSE.
eval(4-3) eq "1" is TRUE. <<<-----
~\Perlscripts>
**Question 2**
(mainly just asking for confirmation)
`"4-3"` is obviously not the same characters as in the string `"1"`. Am I correct that the `eval()` parses my input, evaluates it mathematically, and the result is then essentially placed into a string, `"1"`, which is exactly the same characters as the comparison string `"1"`?
Perl's a bit weird because it's the operators that coerce the data rather than the data deciding what the operators do. Since Perl has a scalar instead of a more specific data type, it figures out if you wants strings or numbers based on what you are doing. If you use numeric operators, Perl will try to convert the operands to numbers.
It does this by ignoring leading whitespace, they taking the decimal digits up to the end of the string or the first non-decimal digit. It will also accept the first decimal point and the decimal digits that follow it. We cover this in Learning Perl, but you can also read about it in perlnumber.
So, the string 4 - 1 is numerically 4, with a warning:
$ perl -wle " print q(4 - 1) + 0 "
Argument "4 - 1" isn't numeric in addition (+) at -e line 1.
4
I think you're asking a slightly different question. Perl does not do math for you. You have an eval in there, and that will execute the string as Perl code. What the Perl code evaluates to is what you get back.

perl false values are not printed

when I print false values in perl I get nothing printed. Probably this is a very simple question, but I searched google without finding an answer.
Code:
print "2 == 2 :", 2 == 2, "\n";
print "2 != 2 :", 2 != 2, "\n";
print "2 == 3 :", 2 == 3, "\n";
print "2 != 3 :", 2 != 3", "\n";
This is the output:
2 == 2:1
2 != 2 :
2 == 3 :
2 != 3 :1
why the false value is not being printed?
Perl doesn't have a strict boolean type - it has a bunch of things that evaluate as 'false' and everything else is true.
Now, here's the thing - false is anything that's numerically zero, or an empty string. Or indeed undef.
So:
print "Zero" if 0;
print "Empty" if '';
print "Undef" if undef;
None will print, because all the conditionals are 'false'.
Now, when you try and create a 'boolean' how should perl know what value to give it?
#!/usr/bin/env perl
use strict;
use warnings;
my $value = !1;
my $othervalue = !'true';
What is $value or $othervalue at this point? I mean, any of 0, 0.00, '' (and a few others) would be 'valid'. But here's the thing - it doesn't matter, because it's a boolean. As long as when you feed it into if it does the right thing, then perl can return whatever it likes.
Perl cheats - it returns from this operation a dualvar - a variable with two values, one for uses in a string context, and the other for use in a numeric context.
You can do a thing that doesn't work otherwise:
use Scalar::Util qw ( isdual dualvar );
print "\$value is dual\n" if isdual $value;
print "Coercing numerically:", 0+$value,"\n";
print "Coercing stringifically:", ''.$value,"\n";
This won't work for normal numerical (or string) values. You can recreate the same with the dualvar function:
my $special = dualvar ( 666, "the beast" );
Meddling with dualvars isn't generally good practice though. Just print explicitly what you want, with a conditional test and you've got no ambiguity there.
The 'false' value has been printed, sort off, don't worry about it.
Perl has a very simple concept of 'false', see the Perl Documentation for more details. The link provided by #jm666 tells more about it. Basically, 0 or "" or undef are all three 'false'.
Your print happened to 'stringify' the special 'false' value, which is the empty string.
You shouldn't expect to be able to print Boolean values. All that you should expect to be able to do with Boolean values is to ask them if they are true or false.
As it happens, you often can print Perl's Boolean values and get a useful result. Most Perl Boolean operations will give you 1 for true and an empty string for false. [Update: Strictly speaking, what you're getting is a dualvar with the values '' and 0.] That's what you're seeing here. The false value is being printed, but it's an empty string.
If you want to see something specific to indicate your false value, then you need to implement that yourself.
print "2 == 3 :", (2 == 3 ? 'true' : 'false'), "\n";
But really, Boolean values aren't intended for displaying.

Understanding return of 0 in numeric comparison

Trying to understand some code which is written as:
if ($txn->result() == 1) { # line 1014
When the return value is a number like 1, 1001, etc no problem. When the return value is 0, I get the infamous (notorious) "Use of uninitialized value in string eq" warning.
How do you specifically test for the LHS as number equal to RHS as number in this situation?
Regardless of how I try, the result in this situation is returning '' where I expected it to be false.
The message you report does not comes from the code you posted. That message comes from eq undef, not from == 0.
$ perl -we'if (123 == 0) { }'
$ perl -we'if (123 == undef) { }'
Use of uninitialized value in numeric eq (==) at -e line 1.
$ perl -we'if (123 eq undef) { }'
Use of uninitialized value in string eq at -e line 1.
You can check if a value is undefined ("uninitialized") using the defined function. That said, I bet it's not needed here. If ->result returns true on success and false on error, you should simply check that.
if ($txn->result()) {
Aside from being simpler, this has the added advantage of avoid undefined warnings if undef is used for false.

Perl : why I can't print !$num? when num is 1, it cannot print 0 [duplicate]

This question already has answers here:
Why does !1 give me nothing in Perl?
(5 answers)
Closed 8 years ago.
print !$num;
When $num is 1, I expect to see 0. But, nothing is printed. why is it? Thank you for any comment.
Here are some tests I tried. It is consistent with my problem.
print 1; # 1
print 0; # 0
print !1; # (nothing)
print !0; # 1
print !1 == 0; # 1
Michael
The “false” boolean in Perl is special value that when evaluated as a string is treated as "", but in a numerical context, it is treated as 0.
That is why when printing the negated true value, you're seeing the empty string:
$ perl -MData::Dump -e 'dd !1'
""
To see the value 0, you must use it in a numerical context. You can do this by simply adding 0 to the value:
$ perl -MData::Dump -e 'dd 0 + !1'
0
For more information on booleans, check perldata - Scalar Values.
According to the docs,
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.
print is evaluating !1 as a string, so it is being treated as a "".
If you evaluate !1 in a numeric context, it will be treated as a 0.
$ perl -MData::Dumper -e'print Dumper !1+!1'
$VAR1 = 0;
In a general sense, there's a variety of values that are true and a variety of values that are false. So not true is valid in a boolean context, but ambiguous when you print it.

When does the difference between a string and a number matter in Perl 5?

If a string in Perl 5 passes looks_like_number, it might as well be a number. For instance,
my $s = "10" + 5;
results in $s being assigned 15.
Are there any cases where a string does not behave like its numeric equivalent would?
When dealing with bitwise operators. 123 ^ 456 is 435, but "123" ^ "456" is "\x05\x07\x05". The bitwise operators work numerically if either operand is a number.
I can only think of one: when checking for truth. Strings that are equivalent to 0, but that are not "0", such as "0.0", "0 but true", "0e0", etc. all pass looks_like_number and evaluate to 0 in numeric context, but are still considered true values.
An equivalent number and string behave differently in hash keys -- or, more generally, any time we stringify a largish number:
my (%g, %h);
$g{ 1234000000000000 } = undef; # '1.234e+015' => undef
$h{'1234000000000000'} = undef; # '1234000000000000' => undef
Note that we are still within the range where Perl can store the number precisely:
> perl -e 'printf qq{%.f\n}, 1234000000000000 + $_ for +1, 0, -1'
1234000000000001
1234000000000000
1233999999999999
DB<1> sub is_num { my $x = shift; "$x " ~~ $x }
DB<2> print is_num(123)
1
DB<3> print is_num('123')
DB<4>