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");
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.
my
operator.use strict
and use warnings
in Perl code. These pragmas disable ancient Perl shenanigans and warn about suspicious operations that might be bugs.@_
; 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.