简体   繁体   中英

Ternary operator in perl yields unexpected result when assigning a variable in the statement

I'm trying to make a transition from php to perl and expectedly running into some weirdness. I cannot understand why one version of my code works vs another.

This fails:

sub tester
{
$return;
($_[0] < 10) ? $return = "youre a youngin" : $return = "youre an old person";
return $return;
}


print "how old are you?";
$a = <>;
chomp $a;

print  tester($a);  #both result in "youre an old person"

however this one works:

sub tester
{
    return ($_[0] < 10) ? "youre a youngin" : "youre an old person";
}


print "how old are you?";
$a = <>;
chomp $a;
print  tester($a);

what is the real difference here?!

It is related to Perl's operator precedence. In Perl,

($_[0] < 10) ? $return = "youre a youngin" : $return = "youre an old fart";

is same as

( ($_[0] < 10) ? $return = "youre a youngin" : $return ) = "youre an old fart";

notice the paren binds to the FRONT.

and this leads to another confusing feature of Perl: conditional lvalues: You can do this (CONDITION? $ASSIGN_A_IF_CONDITION_IS_TRUE: $ASSIGN_B_IF_CONDITION_IS_FALSE) = 2

Here is a fix

($_[0] < 10) ? ($return = "youre a youngin") : ($return = "youre an old fart");

http://codepad.org/MxBAy7wy

EDIT:

However, most people would write

$return = ($_[0] < 10) ? "youre a youngin" : "youre an old fart";

, saving the redundancy of typing the variable twice.

According to Perl and PHP docs, Perl ?: is right-associative and PHP ?: is left-associative. (http://perldoc.perl.org/perlop.html ) (http://php.net/manual/en/language.operators.precedence.php )

Ah, you've discovered why ?: is a bad idea except in trivial cases.

Operator precedence is the problem. You most likely want to do this:

$return = ($_[0] < 10) ? "you're a youngin'" : "you're an old fart";

There are a few other issues with your code, though.

  • You should declare your variables. They aren't declared on first use as in PHP; you do it explicitly with the my operator.
  • You should always, always, always use strict and use warnings in Perl code. These pragmas disable ancient Perl shenanigans and warn about suspicious operations that might be bugs.
  • The first line of a function should usually be unpacking @_ ; there's very little reason to use $_[0] directly in a function. (And it's dangerous to do so, since @_ is aliased; you could change the caller's variables!)

So you probably want something more like this:

use strict;
use warnings;

sub tester {
    my ($age) = @_;
    if ($age < 10) {
        return "you're a youngin'";
    }
    else {
        return "you're an old fart";
    }
}

print "how old are you? ";
my $age = <>;
chomp $age;

print tester($age);

Note that my $x =... declares a single variable and assigns a single value, whereas my ($x, $y, $z) =... declares multiple variables and unpacks a list into them.

my variables are called lexical and only exist within the block where you declare them; they aren't function-scoped like PHP variables. Actually you should probably just read about them in perlsub .

If you write:

sub tester
{
   return ($_[0] < 10) ? "You're a young'un" : "You're an oldie";
}

then you get the result you expect.

It's a precedence thing.

($_[0] < 10) ? ($return = "youre a youngin") : ($return = "youre an old fart");

...works better.

But honestly, no serious Perl programmer would write it like this. First, they would put the following at the top of their program:

use warnings;
use strict;

Second, they would put the argument into a local:

sub tester {
    my $arg = shift;

Third, they would write the conditional in one of two ways:

if ($arg < 10) {
    $return = "you're a youngin";
}
else {
    $return = "you're an old fart";
}

If they came from a Lisp background, they would probably dispense with the $return variable and just write:

return $arg < 10 ? "you're a youngin" : "you're an old fart";

Basically, operator precedence.

I believe $return; is a syntax error. You don't need to declare it - variables in perl and php are scopeless.
In addition = takes precedence over ?: so you need to add () to both assignments.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM