Why does !1 give me nothing in Perl? - 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);

Related

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.

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

Why does Perl think "0 but true" is a number? [duplicate]

Can someone explain what exactly the string "0 but true" means in Perl? As far as I understand, it equals zero in an integer comparison, but evaluates to true when used as a boolean. Is this correct? Is this a normal behavior of the language or is this a special string treated as a special case in the interpreter?
It's normal behaviour of the language. Quoting the perlsyn manpage:
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.
Because of this, there needs to be a way to return 0 from a system call that expects to return 0 as a (successful) return value, and leave a way to signal a failure case by actually returning a false value. "0 but true" serves that purpose.
Because it's hardcoded in the Perl core to treat it as a number. This is a hack to make Perl's conventions and ioctl's conventions play together; from perldoc -f ioctl:
The return value of ioctl (and fcntl) is as follows:
if OS returns: then Perl returns:
-1 undefined value
0 string "0 but true"
anything else that number
Thus Perl returns true on success and false on failure, yet you
can still easily determine the actual value returned by the
operating system:
$retval = ioctl(...) || -1;
printf "System returned %d\n", $retval;
The special string "0 but true" is exempt from -w complaints
about improper numeric conversions.
Additionally to what others said, "0 but true" is special-cased in that it doesn't warn in numeric context:
$ perl -wle 'print "0 but true" + 3'
3
$ perl -wle 'print "0 but crazy" + 3'
Argument "0 but crazy" isn't numeric in addition (+) at -e line 1.
3
The value 0 but true is a special case in Perl. Although to your mere mortal eyes, it doesn't look like a number, wise and all knowing Perl understands it really is a number.
It has to do with the fact that when a Perl subroutine returns a 0 value, it is assumed that the routine failed or returned a false value.
Imagine I have a subroutine that returns the sum of two numbers:
die "You can only add two numbers\n" if (not add(3, -2));
die "You can only add two numbers\n" if (not add("cow", "dog"));
die "You can only add two numbers\n" if (not add(3, -3));
The first statement won't die because the subroutine will return a 1. That's good.
The second statement will die because the subroutine won't be able to add cow to dog.
And, the third statement?
Hmmm, I can add 3 to -3. I just get 0, but then my program will die even though the add subroutine worked!
To get around this, Perl considers 0 but true to be a number. If my add subroutine returns not merely 0, but 0 but true, my third statement will work.
But is 0 but true a numeric zero? Try these:
my $value = "0 but true";
print qq(Add 1,000,000 to it: ) . (1_000_000 + $value) . "\n";
print "Multiply it by 1,000,000: " . 1_000_000 * $value . "\n";
Yup, it's zero!
The index subroutine is a very old piece of Perl and existed before the concept of 0 but true was around. It is suppose to return the position of the substring located in the string:
index("barfoo", "foo"); #This returns 3
index("barfoo", "bar"); #This returns 0
index("barfoo", "fu"); #This returns ...uh...
The last statment returns a -1. Which means if I did this:
if ($position = index($string, $substring)) {
print "It worked!\n";
}
else {
print "If failed!\n";
}
As I normally do with standard functions, it wouldn't work. If I used "barfoo" and "bar" like I did in the second statement, The else clause would execute, but if I used "barfoo" and "fu" as in the third, the if clause would execute. Not what I want.
However, if the index subroutine returned 0 but true for the second statement and undef for the third statement, my if/else clause would have worked.
You may also see the string "0E0" used in Perl code, and it means the same thing, where 0E0 just means 0 written in exponential notation. However, since Perl only considers "0", '' or undef as false, it evaluates to true in a boolean context.
It's hard-coded in Perl's source code, specifically in Perl_grok_number_flags in numeric.c.
Reading that code I discovered that the string "infinity" (case insensitive) passes the looks_like_number test too. I hadn't known that.
In an integer context, it evaluates to 0 (the numeric part at the beginning of the string) and is zero. In a scalar context, it's a non-empty value, so it is true.
if (int("0 but true")) { print "zero"; }
(no output)
if ("0 but true") { print "true"; }
(prints true)
0 means false in Perl (and other languages related to C). For the most part, that's a reasonable behavior. Other languages (Lua for instance) treat 0 as true and provide another token (often nil or false) to represent a non-true value.
One case where the Perl way doesn't work so well is when you want to return either a number or, if the function fails for some reason, a false value. For instance, if you write a function that reads a line from a file and returns the number of characters on the line. A common usage of the function might be something like:
while($c = characters_in_line($file)){
...
};
Notice that if the number of characters on a particular line is 0, the while loop will end before the end of the file. So the characters_in_line function should special case 0 characters and return '0 but true' instead. That way the function will work as intended in the while loop, but also return the correct answer should it be used as a number.
Note that this isn't a built in part of the language. Rather it takes advantage of Perl's ability to interpret a string as a number. So other stings are sometimes used instead. DBI uses "0E0", for instance. When evaluated in numeric context, they return 0, but in boolean context, false.
Things that are false:
"".
"0".
Things that stringify to those.
"0 but true" is not one of those, so it's not false.
Furthermore, Perl returns "0 but true" where a number is expected in order to signal that a function succeeded even though it returned zero. sysseek is an example of such a function. Since the value is expected to be used as a number, Perl is coded to consider it to be a number. As a result, no warnings are issued when it's used as a number, and looks_like_number("0 but true") returns true.
Other "true zeroes" can be found at http://www.perlmonks.org/?node_id=464548.
Another example of "0 but true":
The DBI module uses "0E0" as a return value for UPDATE or DELETE queries that didn't affect any records. It evaluates to true in a boolean context (indicating that the query was executed properly) and to 0 in a numeric context indicating that no records were changed by the query.
I just found proof that the string "0 but true" is actially built into the interpreter, like some people here already answered:
$ strings /usr/lib/perl5/5.10.0/linux/CORE/libperl.so | grep -i true
Perl_sv_true
%-p did not return a true value
0 but true
0 but true
When you want to write a function that returns either an integer value, or false or undef (i.e. for the error case) then you have to watch out for the value zero. Returning it is false and shouldn't indicate the error condition, so returning "0 but true" makes the function return value true while still passing back the value zero when math is done on it.
"0 but true" is a string just like any other but because of perl's syntax it can serve a useful purpose, namely returning integer zero from a function without the result being "false"(in perl's eyes).
And the string need not be "0 but true". "0 but false" is still "true"in the boolean sense.
consider:
if(x)
for x: yields:
1 -> true
0 -> false
-1 -> true
"true" -> true
"false" -> true
"0 but true" -> true
int("0 but true") ->false
The upshot of all of this is you can have:
sub find_x()
and have this code be able to print "0" as its output:
if($x = find_x)
{
print int($x) . "\n";
}
The string ``0 but true'' is still a special case:
for arg in "'0 but true'" "1.0*('0 but true')" \
"1.0*('0 but false')" 0 1 "''" "0.0" \
"'false'" "'Ja'" "'Nein'" "'Oui'" \
"'Non'" "'Yes'" "'No'" ;do
printf "%-32s: %s\n" "$arg" "$(
perl -we '
my $ans=eval $ARGV[0];
$ans=~s/^(Non?|Nein)$//;
if ($ans) {
printf "true: |%s|\n",$ans
} else {
printf "false: |%s|", $ans
};' "$arg"
)"
done
give the following: (note the ``warning''!)
'0 but true' : true: |0 but true|
1.0*('0 but true') : false: |0|
Argument "0 but false" isn't numeric in multiplication (*) at (eval 1) line 1.
1.0*('0 but false') : false: |0|
0 : false: |0|
1 : true: |1|
'' : false: ||
0.0 : false: |0|
'false' : true: |false|
'Ja' : true: |Ja|
'Nein' : false: ||
'Oui' : true: |Oui|
'Non' : false: ||
'Yes' : true: |Yes|
'No' : false: ||
... and don't forget to RTFM!
man -P'less +"/0 but [a-z]*"' perlfunc
... "fcntl". Like "ioctl", it maps a 0 return from the system call
into "0 but true" in Perl. This string is true in boolean
context and 0 in numeric context. It is also exempt from the
normal -w warnings on improper numeric conversions. ...

What does "0 but true" mean in Perl?

Can someone explain what exactly the string "0 but true" means in Perl? As far as I understand, it equals zero in an integer comparison, but evaluates to true when used as a boolean. Is this correct? Is this a normal behavior of the language or is this a special string treated as a special case in the interpreter?
It's normal behaviour of the language. Quoting the perlsyn manpage:
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.
Because of this, there needs to be a way to return 0 from a system call that expects to return 0 as a (successful) return value, and leave a way to signal a failure case by actually returning a false value. "0 but true" serves that purpose.
Because it's hardcoded in the Perl core to treat it as a number. This is a hack to make Perl's conventions and ioctl's conventions play together; from perldoc -f ioctl:
The return value of ioctl (and fcntl) is as follows:
if OS returns: then Perl returns:
-1 undefined value
0 string "0 but true"
anything else that number
Thus Perl returns true on success and false on failure, yet you
can still easily determine the actual value returned by the
operating system:
$retval = ioctl(...) || -1;
printf "System returned %d\n", $retval;
The special string "0 but true" is exempt from -w complaints
about improper numeric conversions.
Additionally to what others said, "0 but true" is special-cased in that it doesn't warn in numeric context:
$ perl -wle 'print "0 but true" + 3'
3
$ perl -wle 'print "0 but crazy" + 3'
Argument "0 but crazy" isn't numeric in addition (+) at -e line 1.
3
The value 0 but true is a special case in Perl. Although to your mere mortal eyes, it doesn't look like a number, wise and all knowing Perl understands it really is a number.
It has to do with the fact that when a Perl subroutine returns a 0 value, it is assumed that the routine failed or returned a false value.
Imagine I have a subroutine that returns the sum of two numbers:
die "You can only add two numbers\n" if (not add(3, -2));
die "You can only add two numbers\n" if (not add("cow", "dog"));
die "You can only add two numbers\n" if (not add(3, -3));
The first statement won't die because the subroutine will return a 1. That's good.
The second statement will die because the subroutine won't be able to add cow to dog.
And, the third statement?
Hmmm, I can add 3 to -3. I just get 0, but then my program will die even though the add subroutine worked!
To get around this, Perl considers 0 but true to be a number. If my add subroutine returns not merely 0, but 0 but true, my third statement will work.
But is 0 but true a numeric zero? Try these:
my $value = "0 but true";
print qq(Add 1,000,000 to it: ) . (1_000_000 + $value) . "\n";
print "Multiply it by 1,000,000: " . 1_000_000 * $value . "\n";
Yup, it's zero!
The index subroutine is a very old piece of Perl and existed before the concept of 0 but true was around. It is suppose to return the position of the substring located in the string:
index("barfoo", "foo"); #This returns 3
index("barfoo", "bar"); #This returns 0
index("barfoo", "fu"); #This returns ...uh...
The last statment returns a -1. Which means if I did this:
if ($position = index($string, $substring)) {
print "It worked!\n";
}
else {
print "If failed!\n";
}
As I normally do with standard functions, it wouldn't work. If I used "barfoo" and "bar" like I did in the second statement, The else clause would execute, but if I used "barfoo" and "fu" as in the third, the if clause would execute. Not what I want.
However, if the index subroutine returned 0 but true for the second statement and undef for the third statement, my if/else clause would have worked.
You may also see the string "0E0" used in Perl code, and it means the same thing, where 0E0 just means 0 written in exponential notation. However, since Perl only considers "0", '' or undef as false, it evaluates to true in a boolean context.
It's hard-coded in Perl's source code, specifically in Perl_grok_number_flags in numeric.c.
Reading that code I discovered that the string "infinity" (case insensitive) passes the looks_like_number test too. I hadn't known that.
In an integer context, it evaluates to 0 (the numeric part at the beginning of the string) and is zero. In a scalar context, it's a non-empty value, so it is true.
if (int("0 but true")) { print "zero"; }
(no output)
if ("0 but true") { print "true"; }
(prints true)
0 means false in Perl (and other languages related to C). For the most part, that's a reasonable behavior. Other languages (Lua for instance) treat 0 as true and provide another token (often nil or false) to represent a non-true value.
One case where the Perl way doesn't work so well is when you want to return either a number or, if the function fails for some reason, a false value. For instance, if you write a function that reads a line from a file and returns the number of characters on the line. A common usage of the function might be something like:
while($c = characters_in_line($file)){
...
};
Notice that if the number of characters on a particular line is 0, the while loop will end before the end of the file. So the characters_in_line function should special case 0 characters and return '0 but true' instead. That way the function will work as intended in the while loop, but also return the correct answer should it be used as a number.
Note that this isn't a built in part of the language. Rather it takes advantage of Perl's ability to interpret a string as a number. So other stings are sometimes used instead. DBI uses "0E0", for instance. When evaluated in numeric context, they return 0, but in boolean context, false.
Things that are false:
"".
"0".
Things that stringify to those.
"0 but true" is not one of those, so it's not false.
Furthermore, Perl returns "0 but true" where a number is expected in order to signal that a function succeeded even though it returned zero. sysseek is an example of such a function. Since the value is expected to be used as a number, Perl is coded to consider it to be a number. As a result, no warnings are issued when it's used as a number, and looks_like_number("0 but true") returns true.
Other "true zeroes" can be found at http://www.perlmonks.org/?node_id=464548.
Another example of "0 but true":
The DBI module uses "0E0" as a return value for UPDATE or DELETE queries that didn't affect any records. It evaluates to true in a boolean context (indicating that the query was executed properly) and to 0 in a numeric context indicating that no records were changed by the query.
I just found proof that the string "0 but true" is actially built into the interpreter, like some people here already answered:
$ strings /usr/lib/perl5/5.10.0/linux/CORE/libperl.so | grep -i true
Perl_sv_true
%-p did not return a true value
0 but true
0 but true
When you want to write a function that returns either an integer value, or false or undef (i.e. for the error case) then you have to watch out for the value zero. Returning it is false and shouldn't indicate the error condition, so returning "0 but true" makes the function return value true while still passing back the value zero when math is done on it.
"0 but true" is a string just like any other but because of perl's syntax it can serve a useful purpose, namely returning integer zero from a function without the result being "false"(in perl's eyes).
And the string need not be "0 but true". "0 but false" is still "true"in the boolean sense.
consider:
if(x)
for x: yields:
1 -> true
0 -> false
-1 -> true
"true" -> true
"false" -> true
"0 but true" -> true
int("0 but true") ->false
The upshot of all of this is you can have:
sub find_x()
and have this code be able to print "0" as its output:
if($x = find_x)
{
print int($x) . "\n";
}
The string ``0 but true'' is still a special case:
for arg in "'0 but true'" "1.0*('0 but true')" \
"1.0*('0 but false')" 0 1 "''" "0.0" \
"'false'" "'Ja'" "'Nein'" "'Oui'" \
"'Non'" "'Yes'" "'No'" ;do
printf "%-32s: %s\n" "$arg" "$(
perl -we '
my $ans=eval $ARGV[0];
$ans=~s/^(Non?|Nein)$//;
if ($ans) {
printf "true: |%s|\n",$ans
} else {
printf "false: |%s|", $ans
};' "$arg"
)"
done
give the following: (note the ``warning''!)
'0 but true' : true: |0 but true|
1.0*('0 but true') : false: |0|
Argument "0 but false" isn't numeric in multiplication (*) at (eval 1) line 1.
1.0*('0 but false') : false: |0|
0 : false: |0|
1 : true: |1|
'' : false: ||
0.0 : false: |0|
'false' : true: |false|
'Ja' : true: |Ja|
'Nein' : false: ||
'Oui' : true: |Oui|
'Non' : false: ||
'Yes' : true: |Yes|
'No' : false: ||
... and don't forget to RTFM!
man -P'less +"/0 but [a-z]*"' perlfunc
... "fcntl". Like "ioctl", it maps a 0 return from the system call
into "0 but true" in Perl. This string is true in boolean
context and 0 in numeric context. It is also exempt from the
normal -w warnings on improper numeric conversions. ...