Understanding return of 0 in numeric comparison - perl

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.

Related

Perl: undef element in array

I defined some elements in an array:
my #arrTest;
$arrTest[0]=1;
$arrTest[2]=2;
#Result for #arrTest is: (1, undef, 2)
if($arrTest[1]==0)
{
print "one\n";
}
elsif($arrTest[1] == undef)
{
print "undef\n";
}
I think it should print "undef". But it prints "one" here...
Does it mean $arrTest[1]=undef=0?
How can I modify the "if condition" to distinguish the "undef" in array element?
The operator == in the code $arrTest[1] == 0 puts $arrTest[1] in numeric context and so its value gets converted to a number if needed, as best as the interpreter can do, and that is used in the comparison. And when a variable in a numeric test hasn't been defined a 0 is used so the test evaluates to true (the variable stays undef).
Most of the time when this need be done we get to hear about it (there are some exceptions) -- if we have use warnings; that is (best at the beginning of the program)† Please always have warnings on, and use strict. They directly help.
To test for defined-ness there is defined
if (not defined $arrTest[1]) { ... }
† A demo
perl -wE'say "zero" if $v == 0; say $v; ++$v; say $v'
The -w enables warnings. This command-line program prints
Use of uninitialized value $v in numeric eq (==) at -e line 1.
zero
Use of uninitialized value $v in say at -e line 1.
1
Note how ++ doesn't warn, one of the mentioned exceptions.

Where is the error "Use of uninitialized value in string ne" coming from?

Where is the uninitialised value in the below code?
#!/usr/bin/perl
use warnings;
my #sites = (undef, "a", "b");
my $sitecount = 1;
my $url;
while (($url = $sites[$sitecount]) ne undef) {
$sitecount++;
}
Output:
Use of uninitialized value in string ne at t.pl line 6.
Use of uninitialized value in string ne at t.pl line 6.
Use of uninitialized value in string ne at t.pl line 6.
Use of uninitialized value in string ne at t.pl line 6.
You can't use undef in a string comparison without a warning.
if ("a" ne undef) { ... }
will raise a warning. If you want to test if a variable is defined or not, use:
if (defined $var) { ... }
Comments about the original question:
That's a strange way to iterate over an array. The more usual way of doing this would be:
foreach my $url (#sites) { ... }
and drop the $sitecount variable completely, and don't overwrite $url in the loop body. Also drop the undef value in that array. If you don't want to remove that undef for some reason (or expect undefined values to be inserted in there), you could do:
foreach my $url (#sites) {
next unless defined $url;
...
}
If you do want to test for undefined with your form of loop construct, you'd need:
while (defined $sites[$sitecount]) {
my $url = $sites[$sitecount];
...
$sitecount++;
}
to avoid the warnings, but beware of autovivification, and that loop would stop short if you have undefs mixed in between other live values.
The correct answers have already been given (defined is how you check a value for definedness), but I wanted to add something.
In perlop you will read this description of ne:
Binary "ne" returns true if the left argument is stringwise not equal
to the right argument.
Note the use of "stringwise". It basically means that just like with other operators, such as ==, where the argument type is pre-defined, any arguments to ne will effectively be converted to strings before the operation is performed. This is to accommodate operations such as:
if ($foo == "1002") # string "1002" is converted to a number
if ($foo eq 1002) # number 1002 is converted to a string
Perl has no fixed data types, and relies on conversion of data. In this case, undef (which coincidentally is not a value, it is a function: undef(), which returns the undefined value), is converted to a string. This conversion will cause false positives, that may be hard to detect if warnings is not in effect.
Consider:
perl -e 'print "" eq undef() ? "yes" : "no"'
This will print "yes", even though clearly the empty string "" is not equal to not defined. By using warnings, we can catch this error.
What you want is probably something like:
for my $url (#sites) {
last unless defined $url;
...
}
Or, if you want to skip to a certain array element:
my $start = 1;
for my $index ($start .. $#sites) {
last unless defined $sites[$index];
...
}
Same basic principle, but using an array slice, and avoiding indexes:
my $start = 1;
for my $url (#sites[$start .. $#sites]) {
last unless defined $url;
...
}
Note that the use of last instead of next is the logical equivalent of your while loop condition: When an undefined value is encountered, the loop is exited.
More debugging: http://codepad.org/Nb5IwX0Q
If you, like in this paste above, print out the iteration counter and the value, you will quite clearly see when the different warnings appear. You get one warning for the first comparison "a" ne undef, one for the second, and two for the last. The last warnings come when $sitecount exceeds the max index of #sites, and you are comparing two undefined values with ne.
Perhaps the message would be better to understand if it was:
You are trying to compare an uninitialized value with a string.
The uninitialized value is, of course, undef.
To explicitely check if $something is defined, you need to write
defined $something
ne is for string comparison, and undef is not a string:
#!/usr/bin/perl
use warnings;
('l' ne undef) ? 0 : 0;
Use of uninitialized value in string ne at t.pl line 3.
It does work, but you get a [slightly confusing] warning (at least with use warnings) because undef is not an "initialized value" for ne to use.
Instead, use the operator defined to find whether a value is defined:
#!/usr/bin/perl
use warnings;
my #sites = (undef, "a", "b");
my $sitecount = 1;
my $url;
while (defined $sites[$sitecount]) { # <----------
$url = $sites[$sitecount];
# ...
$sitecount++;
}
... or loop over the #sites array more conventionally, as Mat explores in his answer.

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. ...

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);

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. ...