print result of comparison operators [duplicate] - 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)

Related

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

There's "0 but true", but is there "42 but false" in perl?

As per the question. I know there's "0 but true" which is true in a boolean context but false otherwise, but can return something false in a boolean context but with a non-zero value (the obvious place for this is return statuses where 0 is success and anything else is an error).
No. (Except for fun with dualvars and overloaded objects)
The truthiness of a Perl scalar depends primarily on the string value. If no string value is present, the numeric field will be used.
False values are: undef, "", 0, and to avoid issues by testing the stringification first: "0".
Not everything that is numerically zero evaluates to false: "0E0" is true, so is the more self-documenting "0 but true". The latter is special-cased to avoid non-numeric warnings.
However, enter dualvars. The numeric and stringy field of a scalar don't have to be in sync. A common dualvar is the $! variable that is the errno in numeric context, but a error string containing a reason as a string. So it would be possible to create a dualvar with numeric value 42 and string value "", which will evaluate to false.
use Scalar::Util qw/dualvar/;
my $x = dualvar 42, "";
say $x; # empty string
say 0+$x; # force numeric: 42
say $x ? 1 : 0; # 0
And then overloaded objects. Instances of the following class will stringify nicely, but still evaluate to false in a boolean context:
package FalseString;
sub new {
my ($class, $str) = #_;
bless \$str => $class;
}
use overload
'""' => sub { ${shift()} },
'bool' => sub { 0 };
Test:
my $s = FalseString->new("foo");
say $s;
say $s ? "true" : "false";
Prints
foo
false

hashref check using if condition returns null

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'} ) ) {

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)

Why does !1 give me nothing in Perl?

This is strange.
The following:
$sum = !0;
print $sum;
prints out 1 as you would expect. But this
$sum = !1;
print $sum;
prints out nothing. Why?
Be careful: what you've written isn't doing what you think it's doing. Remember, perl has no real boolean datatype. It's got scalars, hashes, lists, and references. The way it handles true/false values, then, is contextual. Everything evaluates to "true" in perl except for undefined variables, the empty list, the empty string, and the number 0.
What your code is doing, then, is taking the inverse of a value that evaluates to "false", which can be anything which is not in the list above. By convention and for simplicity's sake, perl returns 1 (though you should not rely on that; it could very well return a list containing a series of random numbers, because that will evaluate to "true" as well.)
A similar thing happens when you ask for the inverse of a value that evaluates to "true." What's actually being printed out is not "nothing," it's the empty string (''), which, as I mentioned, evaluates to "false" in boolean expressions. You can check this:
print "This evaluates to false\n" if( (!1) eq '');
If you're asking for why perl spits out the empty string instead of one of the other "false" values, well, it's probably because perl is made to handle strings and that's a perfectly reasonable string to hand back.
The operators that only return a boolean result will always return 1 for true and a special false value that's "" in string contexts but 0 in numeric contexts.
Here's an addendum to the other great answers you've already gotten.
Not's Not Not
Consider the following code that tests each of Perl's 'not' operators:
#!/usr/bin/perl
use strict;
use warnings;
for( '!1', 'not 1', '~0' ) {
my $value = eval;
my $zero_plus = 0 + $value;
print join "\n",
"\nExpression: $_",
"Value: '$value'",
"Defined: " . defined $value,
"Length: " . length($value),
"Plus: " . +$value,
"Plus Zero: '$zero_plus'",
'';
}
print "\nTest addition for a literal null string: ";
print 0+'', "\n";
use Scalar::Util qw(dualvar);
{ # Test a dualvar
my $value = dualvar 0, '';
my $zero_plus = 0+$value;
print join "\n",
"\nExpression: dualvar",
"Value: '$value'",
"Defined: " . defined $value,
"Length: " . length($value),
"Plus: " . +$value,
"Plus Zero: '$zero_plus'",
'';
}
Executing it results in the following. Notice the warning message:
Argument "" isn't numeric in addition (+) at test.pl line 21.
Expression: !1
Value: ''
Defined: 1
Length: 0
Plus:
Plus Zero: '0'
Expression: not 1
Value: ''
Defined: 1
Length: 0
Plus:
Plus Zero: '0'
Expression: ~0
Value: '4294967295'
Defined: 1
Length: 10
Plus: 4294967295
Plus Zero: '4294967295'
Test addition for a literal null string: 0
Expression: dualvar
Value: ''
Defined: 1
Length: 0
Plus:
Plus Zero: '0'
From this we learn several things.
The first two items are not all that exciting:
!1 and not 1 behave in basically the same way.
Unsurpisingly, ~1 is different (it's the bitwise not).
Now, the interesting item:
While we do get a warning for line 21 (0+''), there is no warning generated when we add 0+!1.
It Takes Two to Tangle
Something fishy is happening, and that fishiness has to do with special scalar contexts in Perl. In this case, the distinction between numeric and string contexts. And the ability to create a variable that has different values in each context, aka a dual variable.
It looks like !1 returns a dual variable that returns 0 in numeric context and the null string in string context.
The dualvar test at the end shows that a homemade dualvar works the same way as !1.
But It's A Good Thing
Like many Perl features, dual variables seem at first to defy expectations, and can be confusing. However, like those other features, used appropriately they make life much easier.
As far as I know, a dualvar of 0 and '' is the only defined value that will return false in all scalar contexts. So it is a very sensible return value for !1. One could argue that undef is a good false result, but then an uninitialized variable is not distinguishable from a false value. Also, attempts to print or add the results of booleans would then be plagued with unnecessary warnings.
Another famous dualvar is $! or $OS_ERROR if you use English. In numeric form, you get the error code, in string form, the error code is translated for you.
It's Not Nothing, It's Empty, But It's Nought
So in summary, you aren't getting nothing, you aren't getting an empty string, and you aren't getting zero.
You are getting a variable that is both an empty string and 0 at the same time.
The ! operator does boolean operations. "" (The empty string) is just as false as 0 is. 1 is a convenient true value. ! shouldn't be relied on to do anything other than produce some true/false value. Relying on the exact value beyond that is dangerous and may change between versions of Perl.
See perldoc perlsyn:
Truth and Falsehood
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.
There, if you print the value as a number, you will get 0 rather than the empty string:
printf "%d\n", $_ for map { !$_ } (1, 0);
or
print 0 + $_, "\n" for map { !$_ } (1, 0);
Compare those to
printf "%s\n", $_ for map { !$_ } (1, 0);
and
print $_, "\n" for map { !$_ } (1, 0);