Re: variable set to 0 ? 0 : 1
by Arien (Pilgrim) on Sep 06, 2002 at 05:11 UTC
|
if ($status == 0) {
return 0;
} else {
return 1;
}
which makes more sense as this:
return $status;
or if you only want to return 1 and 0 instead of just "true" and "false":
return $status ? 1 : 0;
— Arien | [reply] [d/l] [select] |
|
return !!$status;
but that's probably a little too idiomatic for this OP.
Well It's better than the Abottoire, but Yorkshire! | [reply] [d/l] |
|
Nice golf, but your solution never returns 0, which is what the original snippet does. Furthermore, if $status is '0E0' or '0.0' it returns 1, because they both are true values, though numerically zero.
See:
for ( 0, 0.0, "0", "0.0", "0E0", 1, "1" ) {
print $_, "\t", !!$_, "\t", ( $_==0 ? 0 : 1 ), "\n";
}
prints out
0 0
0 0
0 0
0.0 1 0
0E0 1 0
1 1 1
1 1 1
Best regards
Antonio Bellezza
Update:
As pointed out in other posts, the same behaviour of "0.0" and "0E0" is true for strings not representing numbers, which have true values, but behave as 0 in numeric comparison. The difference is a warning of type
Argument "xyz" isn't numeric in numeric eq (==) at - line 3.
when -w is enabled.
| [reply] [d/l] |
|
|
That's how I used to do it in C/C++ before it had a bool type, when it was necessary to canonize the value.
If that's too idiomatic, using return asbool($status) where that's an inlined function would be readable and just as efficient.
Note that it does a bit more than it does in a stronly-typed language. What if $status is not an int at all? The normal boolism is to treat undef and empty strings as false, also, and in one known case 0e1 is used as zero-but-true. The original test will be different from that; the !! idiom preserves it.
—John
| [reply] [d/l] [select] |
|
|
return $status && 1; # canonize false, leave true as-is
for completness sake.
update: I got that backwards. && returns the last part evaluated, and skips the right side if the left already determines the outcome. So, if $status is false it returns it unchanged; if true it evaluates the right hand side and gets a numeric 1. It canonizes true, leaves false as-is.
$status || 0; will return $status unchanged if true, and check the rhs if false. So that canonizes false and returns true unchanged. | [reply] [d/l] [select] |
|
|
|
-sauoq
"My two cents aren't worth a dime.";
| [reply] [d/l] |
|
|
|
-sauoq
"My two cents aren't worth a dime.";
| [reply] [d/l] [select] |
|
Someone should have pointed out that your code above is not equivalent to the original.
You are right. After explaining the exact meaning of the snippet, I just suggested a more sensible, although not exactly equivalent, way. :-)
— Arien
| [reply] |
Re: variable set to 0 ? 0 : 1
by dws (Chancellor) on Sep 06, 2002 at 05:12 UTC
|
Can someone explain just how that == is working or what its doing?
By operator precedence,
return $status == 0 ? 0 : 1;
is treated as
return ($status == 0) ? 0 : 1;
which is a stylistic way of saying "return 0 if $status is 0, otherwise return 1".
Other ways to write this include
if ( $status == 0 ) {
return 0;
} else {
return 1;
}
which is what you might expect a junior C programmer to write, or
return 0 if $status == 0;
return 1;
which you might see a Perl programmer write if they eschew the trinary operator.
| [reply] [d/l] [select] |
Re: variable set to 0 ? 0 : 1
by Aristotle (Chancellor) on Sep 06, 2002 at 06:05 UTC
|
The explanation has already been given exhaustively, but I want to expand a bit on semantics here.
Returning zero in Perl is usually a bad meme. It is ok if you actually meant to return a numeric zero, but if you mean to return "false", the Perlish way is to return an empty list <update> in list context and undef otherwise. </update> This is because by returning 0 you return a single-element list, which evaluates to true in list context. The code would then look like this:
return $status == 0 ? (wantarray ? () : undef) : 1;
or maybe better
return 1 if $status == 0;
return; # a return by itself implicitly returns an empty list
Another pitfall may or may not be the == 0. Is it meant to test falseness? If so, it is not precise. Perl understands the notion of an undefined value <update> and also considers a defined but empty string as well as a literal string "0" to be false </update>, which are not the same as zero, so this test is broken if it means to check falseness. In all likelihood, the programmer there should have written
return 1 if $status;
return;
Updated: thanks ++Flexx. Moved one code example, added a few small but important bits.
Makeshifts last the longest. | [reply] [d/l] [select] |
|
#!/usr/local/bin/perl -wl
use strict;
sub a_func_that_returns_false { return 0; }
sub your_func_that_returns_false { return (); }
sub func_that_expects_string_boolean_and_num {
my $str = shift;
my $bool = shift;
my $num = shift;
print "CALLED FUNC: ", $str;
print " bool was ", ($bool ? "true" : "false");
print " num was ", (20 < $num ? "bigger" : "smaller"), " then tw
+enty";
}
&func_that_expects_string_boolean_and_num
("the zero way", &a_func_that_returns_false(), 42);
&func_that_expects_string_boolean_and_num
("the empty list way", &your_func_that_returns_false(), 42);
__DATA__
laptop:~> monk.pl
CALLED FUNC: the zero way
bool was false
num was bigger then twenty
CALLED FUNC: the empty list way
bool was true
Use of uninitialized value in numeric lt (<) at monk.pl line 12.
num was smaller then twenty
Bottom line: there's no substite for using wantarray
to check your calling context, and acting appropriately
(except perhaps extensively documenting that your method may
not work the way people think and making it their
responsibility to force the calling context)
Update: good point blakem
| [reply] [d/l] |
|
there's no substite for using wantarray to check your calling context
Interesting example, though I fail to see how wantarray will help in this case:
sub use_wantarray { return wantarray ? () : 0 }
Wont work properly in your example either.... Note that the above sub is equivalent* to the recommended way to return false, i.e. simply return:
sub recommended_way { return; }
* except when used in void context, but that isn't relevant here.
-Blake
| [reply] [d/l] [select] |
|
... if you mean to return "false", the Perlish way is to return an empty list. This is because by returning 0 you return a single-element list, which evaluates to true in list context.
I feel the risk of that happening is mildly exaggerated. :-)
If you directly evaluate the return value of the sub for truth you supply the sub a Boolean context, and there will be no problem.
To run into problems, you'd have to call the sub in a list context, save the list of 1 return value and then evaluate that in scalar context. But then the problem would be evaluating a list in scalar context when you didn't mean to.
— Arien
| [reply] |
|
| [reply] |
|
Another pitfall may or may not be the == 0. Is it
meant to test falseness? If so, it is
not precise. Perl understands the notion of an
undefined value, which is not the
same as zero, so this test is broken if it
means to check falseness.
Well, accutally.... it's true that undefined is not the
"same" as zero, but they are numericly equal. As you
can see, it generates a warning, but it does evaluate to true...
laptop:~> perl -wle 'print "TrUe" if undef == 0'
Use of uninitialized value in numeric eq (==) at -e line 1.
TrUe
A better example as to why you wouldn't want to use
"$status == 0" as a test for truth is non numeric strings.
the string "foo" is true, but it is numericly equal to 0...
laptop:~> perl -le 'print "TrUe" if "foo" == 0'
TrUe
laptop:~> perl -le 'print "TrUe" if "foo"'
TrUe
| [reply] [d/l] [select] |
|
return 1 if $status == 0;
return; # a return by itself implicitly returns an empty list
It's true that return by itself returns an empty list in list context. But it returns undef in scalar context -- not scalar( () )! ;)
Updated: Simply added a quote of what I was refering to, since the thread grew quite long. Improved punctuation to boost readability. Removed unneccesary extra link to return.
| [reply] [d/l] [select] |
|
| [reply] |
|
| [reply] |
Re: variable set to 0 ? 0 : 1
by Zaxo (Archbishop) on Sep 06, 2002 at 05:14 UTC
|
That is the trinary operator ?:. It parses like this: return (($status == 0) ? 0 : 1);. The first of the terms is evaluated in bool context. If true, the whole trinary takes the value of the expression after the question mark. If false, it takes the value after the colon.
If $status is an instance of a class with overloaded operators, it may not return a simple value. Or else it may be a floating point value, with the accompanying accuracy problems in comparisons. This expression forces $status into numeric context and converts any non-zero $status to 1. The returned value is a perl numeric type, whatever $status may be.
Update: By the way, your title suggests you misread the == operator as assignment. It's numeric comparison for equality, instead. Minor clarification in text.
After Compline, Zaxo
| [reply] [d/l] |
Re: variable set to 0 ? 0 : 1
by theorbtwo (Prior) on Sep 06, 2002 at 05:15 UTC
|
This statement will return 0 if the $status variable is zero, or 1 if it is not. I'm not sure if you don't understand the precidence issues here, or if you don't understand what the ?: operator is. If it's the former, B::Deparse is often good for answering these sorts of questions; the correct precidence is return((($status == 0) ? 0 : 1));. I show how to derive this in Re: Ternary Operator: Condition-Negation.
If it's the later, I suggest reading about the Conditional Operator in perlop. In short, the conditional operator (also called the ternary operator, since it's the only three-valued operator in common (programming) use) is a strange form of if, written as conditional ? if-true : if-false. If conditional is true, the value of the operator is if-true, otherwise the value is if-false.
In the spirit of TIMTOWTID, these stanzas are all (nearly) equivlent:
return $status == 0 ? 0 : 1;
return !!$status; # Checks if $status is true or not, not if it is e
+xactly zero; "" or undef are false, but not == 0.
if ($status == 0) {
return 0;
} else {
return 1;
}
Probably, in the code $status ends up being a count, but the implementor only wanted to gaurntee that if $status is nonzero, a true value is returned, so they could change the function to do less work in the future.
Update: fixed typo. Thanks, blyman.
Warning: Unless otherwise stated, code is untested. Do not use without understanding. Code is posted in the hopes it is useful, but without warranty. All copyrights are relinquished into the public domain unless otherwise stated. I am not an angel. I am capable of error, and err on a fairly regular basis. If I made a mistake, please let me know (such as by responing to this node).
| [reply] [d/l] [select] |
Re: variable set to 0 ? 0 : 1
by talexb (Chancellor) on Sep 06, 2002 at 13:02 UTC
|
Well. This is a pet peeve of mine.
Why do programmers try to do their job with as few brackets as possible? I would much rather write that as
return ( ( $status == 0 ) ? 0 : 1 );
To show that we are
- Testing status against zero, and
- Returning 0 if the test is successful, otherwise returning 1
Use more brackets and the explanation is much easier!
To put that into English, this returns 0 if the status value is 0; for all other values of status, it returns 1. So you could paraphrase this as "Did the routine return a non-zero status?"
--t. alex
but my friends call me T.
| [reply] [d/l] [select] |
|
Because lots of brackets (parens to those of us on this side of the puddle) often make code harder to read even if they make it easier to explain. I would venture a guess that most veteran programmers aren't spending the majority of their time writing code that is meant to be read by novices.
They also make it more difficult to write. Your example, with two sets of parens, requires 8 more keystrokes if you count the shifts. That could add up to 12 inches or more of fingertip movement. When you write a lot of code that can be a very real concern.
I'm not at all suggesting that one should write the leanest code possible, and I want to make that clear. A good rule of thumb is that you should write your code so that someone with skills comparable to your own will be able to easily read it. Consistency in your style will help you achieve that more than anything else. As our style evolves, our code generally becomes less cluttered as a matter of course.
Of the variations below, all of which do the same thing, I prefer the last two.
return ( ( $status == 0 ) ? 0 : 1 ); # Too cluttered.
return ( $status == 0 ) ? 0 : 1; # Misleading.
return ( $status == 0 ? 0 : 1 ); # Clear
return $status == 0 ? 0 : 1; # Clean and clear.
-sauoq
"My two cents aren't worth a dime.";
| [reply] [d/l] |
|
return ( ( $status == 0 ) ? 0 : 1 ); # Readable, clear.
return $status == 0 ? 0 : 1; # Confusing. Precedence?
I *think* I know what the second line does, but I'm not 100% sure. Blame my 15 years of programming in C, but I have to use brackets when I write a return statement. If that means I'm writing C in Perl, so be it.
I also like to put brackets around a conditional, to highlight that there's a logic test going on. I know that operator precedence will take care of it without brackets, but why strain my brain.
Really, this is a tempest in a teapot. My Dad had a wonderful sentence that he claimed made sense, if only it were punctuated correctly: Smith, where Jones had had had had had had had had had had had the examiner's approval. Perfectly understandable: no punctuation is necessary, is it?
--t. alex
but my friends call me T.
| [reply] [d/l] [select] |
|
|
|
|
return
$status == 0
? 0
: 1;
Yes, it seems unnecessarily expansive for this simple case... but I probably wouldn't do it for this simple case.
I would, and do, do this for situations such as:
return
@things = $obj->get_current_list_of_things()
? grep /$wanted/, @things
: $obj->default_things;
# o.k., it's a contrived example. gimme a break.
Predicate and two lemmas, each on its own line.
| [reply] [d/l] [select] |
Re: variable set to 0 ? 0 : 1
by zakzebrowski (Curate) on Sep 06, 2002 at 12:57 UTC
|
<shameless_plug>For more fun with ?, see this node, my first (and so far only) obfuscated attempt...</shameless_plug>
----
Zak
"There is no room in this country for hyphenated Americanism" ~ Theodore Roosevelt (1915) | [reply] |
Re: variable set to 0 ? 0 : 1
by Wally Hartshorn (Hermit) on Sep 06, 2002 at 19:43 UTC
|
Since I don't think anyone has mentioned it, I just thought I would pop in here and emphasize that this is not a feature of the "return" statement. A generic example might be:
$vacation_days = ($seniority > 5) ? 15 : 10;
which is equivalent to:
if ($seniority > 5) {
$vacation_days = 15;
}
else {
$vacation_days = 10;
}
| [reply] [d/l] [select] |
Re: variable set to 0 ? 0 : 1
by nmerriweather (Friar) on Sep 08, 2002 at 01:30 UTC
|
i've never used the trinary operator before -- most of my subs w/returns give back a #, not a true/false
i understand its use for return statements, but am a little unclear about other ways to use it (perhaps changing 1/0 to
'true'/'false' or some other manipulation of a variable?)
i was hoping some people would be willing to share some other examples/samples/instances using this operator is good/appropriate for
| [reply] |
|
#! perl -sw
use strict;
my (@aboveC, @cOrLess);
while (<DATA>) {
# $1 := name, $2 := grade
m/^(\w+)\s+([a-f][+-]?)$/i;
# if the grade is one of these
0<= index('A+ A A- B+ B B- C+', uc($2), 0 )
# add name here if not add name here
? $aboveC[@aboveC] : $cOrLess[@cOrLess] = $1;
}
print "Above C students: @aboveC\n";
print "C or Less students: @cOrLess\n";
__DATA__
homer f
bart d-
marge c+
lisa a
which gives
C:\test>195952
Above C students: marge lisa
C or Less students: homer bart
C:\test>
Well It's better than the Abottoire, but Yorkshire! | [reply] [d/l] [select] |
|
I have to admit being excited about this construct the first time I saw it, though I don't know if I've ever really used it....
push(@{ $whichone ? \@arr1 : \@arr2 }, $element);
-Blake
| [reply] [d/l] |
|
|
I usually use it to visually unclutter code that would otherwise be an if with tiny blocks. It can be used in void context for something like
$i == 15 ?
push @str, $_ :
$j = $i += 1;
or you can "chain" ternary operators by using another ternary as the false-branch of the previous:
my $res =
$cmd eq "add" ? $x + $y :
$cmd eq "sub" ? $x - $y :
$cmd eq "mul" ? $x * $y :
$cmd eq "div" ? $x / $y :
undef;
which would otherwise have to be a hideously ugly and thrice as repetitive thing like this:
my $res;
if ($cmd eq "add") { $res = $x + $y }
elsif($cmd eq "sub") { $res = $x - $y }
elsif($cmd eq "mul") { $res = $x * $y }
elsif($cmd eq "div") { $res = $x / $y }
else { $res = undef }
Makeshifts last the longest. | [reply] [d/l] [select] |
|
Set $max to the maximum of $x vs $y:
$max = $x > $y ? $x : $y;
-Blake
| [reply] [d/l] [select] |
Re: variable set to 0 ? 0 : 1
by somniculosus (Initiate) on Sep 08, 2002 at 14:36 UTC
|
it does not set $status to 0, it merely tests whether status is *equal to* zero (remember == tests for numeric equality) and returns 0 if yes, and 1 if not.
here, a lengthier version:
if ($status == 0) {
return 0;
} else {
return 1;
}
| [reply] [d/l] [select] |