Re: conditional print. Is correct to use it?
by choroba (Cardinal) on Oct 27, 2020 at 12:04 UTC
|
print "My homework: $fo" ; # prints "My homework: " and exits
No, it doesn't exit. It continues running the program on the next line.
print 'My homework: ',($fo || 'Roses are red');
There are only few values considered false in Perl: an undefined value, empty string, 0, and the string "0". In this case, it's the empty string, so you see the alternative value.
$fo + 2 || 8
An empty string in numeric context is treated as zero. 0 + 2 is two which is true, so no need to substitute 8.
$fo + 0
See above. 0 + 0 = 0 and that's what we see.
$fo + 0 || 8
Again, an empty string in numeric context is 0, 0 + 0 is 0 which is false, so we see 8.
Modern Perl explains context in a nice and simple way: see Context.
map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
| [reply] [d/l] [select] |
|
Your complete list of false values is one of those "well known" facts that I cannot find the documentation for. The list does appear in the second paragraph of the documentation of the function defined, but it does not claim to be Perl's definition of 'false'. Can you suggest a better reference.
| [reply] |
|
See "Scalar values" in perldata.
map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
| [reply] [d/l] |
|
| [reply] |
|
Re: conditional print. Is correct to use it?
by davido (Cardinal) on Oct 27, 2020 at 15:25 UTC
|
Is your question about style, or about behavior? There's nothing surprising to me about the behaviors you're describing, but maybe there's an expectations vs reality gap.
You can use Devel::Peek to inspect the actual contents of a scalar.
You can use perldata to learn about what Perl sees as truth and falsehood.
You can refer to perlop to see the precedence list, where || is lower than +.
You can use perl -MO=Deparse,-p,-x9 -e 'print "we have ", ($fo + 2 || 8), " beans";' to see how that parses, and how precedence rules apply. That last one produces:
perl -MO=Deparse,-p,-x9 -e 'print "we have ", ($fo + 2 || 8), " beans"
+;'
print('we have ', (($fo + 2) || 8), ' beans');
-e syntax OK
| [reply] [d/l] [select] |
|
Is more about style. I'm in the middle of an iteration. The known route would be:
put an if loop before -> to fix $variable -> and then print "something $variable something"... to a file.
I'm exploring to include the loop directly inside the print line. Start printing "something" to a file -> then include a mini loop to check the current status of the variable and then finish printing "something".
what strategy would be more correct in your opinion? "if(true){a} else {b}" or just (a||b)
(are both equally correct?)
Note: (About why not write just: my $fo; I have a bunch of variables to initialize. Some are expected to be numeric, other will receive a chain. I want to remind who is who. This is the reason to express specifically the empty chain here. (i.e: my $fo = q{}; my $bar = 0;... instead to just write: my ($fo, $bar)
| [reply] |
|
"if(true){a} else {b}" or just (a||b)
(are both equally correct?)
A statement block like if(true){a} else {b} does not evaluate to
any value (but see Note 1 below), but an expression like (a||b) always does.
Therefore, IMHO it's not correct to say these are equivalent or "equally correct." The
if/else-statement block can be made to have an effect
equivalent to the expression, but only if the a b
expressions or statement(s) have the correct side effects.
An expression can always be incorporated into another expression — if
precedence is handled properly! A statement cannot be
incorporated into another statement unless you contort your program
logic with some sort of usually unnecessary eval nonsense. E.g.:
Win8 Strawberry 5.8.9.5 (32) Wed 10/28/2020 15:06:58
C:\@Work\Perl\monks
>perl -Mstrict -Mwarnings
my $x; # undefined/false
my $y = 'default string';
my $side;
if (not $x) { $side = $y; } # true clause has side effect
# $side = $y unless $x; # a more terse alternative
printf "side effect '%s' logical-or '%s' ternary '%s' \n",
$side, ($x || $y), $x ? $x : $y;
^Z
side effect 'default string' logical-or 'default string' ternary 'de
+fault string'
Notes:
- An if- or if/else-statement block like
if (CONDITION) { statements(s)
}
or
if (CONDITION) { statements(s)
} else { statements(s) }
will return a value from a subroutine if it is the last thing
executed in the subroutine, but this behavior is inherent to the
behavior of subroutines, and not directly related to the behavior of
conditional statement blocks.
Update: To be more precise, what is returned from a
subroutine that has no explicit return statement is the
value of the last statement or expression executed in the subroutine.
So in the subroutine
sub func {
...
...
if ($x) { foo(); bar(); } else { fee(); fie(); }
}
the return value of bar() is returned by func() if
$x is true, that of fie() if $x is false.
Win8 Strawberry 5.8.9.5 (32) Wed 10/28/2020 22:49:24
C:\@Work\Perl\monks
>perl -Mstrict -Mwarnings
printf "'%s' returned from true clause \n", func(1);
printf "'%s' returned from false clause \n", func();
sub func {
my $x = shift;
printf "x is %-7s", $x ? 'true' : 'false';
if ($x) { foo(); bar(); } else { fee(); fie(); }
}
sub foo { return 'from ' . (caller 0)[3]; }
sub bar { return 'from ' . (caller 0)[3]; }
sub fee { return 'from ' . (caller 0)[3]; }
sub fie { return 'from ' . (caller 0)[3]; }
^Z
x is true 'from main::bar' returned from true clause
x is false 'from main::fie' returned from false clause
Give a man a fish: <%-{-{-{-<
| [reply] [d/l] [select] |
Re: conditional print. Is correct to use it?
by duelafn (Parson) on Oct 27, 2020 at 12:01 UTC
|
In my opinion, the only thing to do with unexpected values is die:
# ... but something forrible happens instead...
die "Expected a value for fo" unless defined($fo) and length($fo);
Hard crashes have a way of getting fixed quickly. Anything else tends to cause odd behavior that is hard to track down.
Note: $fo is initiaslized to an empty string. Use just my $fo; do declare an uninitialized (undefined) value.
In response to "we have 8 beans", ($fo + 0 || 8) is parsed as ($fo + (0 || 8)) due to precedence. Update: silly me, ignore this.
| [reply] [d/l] [select] |
|
> ($fo + 0 || 8) is parsed as ($fo + (0 || 8)) due to precedence.
It's not.
perl -MO=Deparse,-p -e 'print $fo + 0 || 8'
print((($fo + 0) || 8));
map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
| [reply] [d/l] [select] |
Re: conditional print. Is correct to use it?
by kcott (Archbishop) on Oct 28, 2020 at 06:42 UTC
|
G'day pvaldes,
In terms of style, I'd say it's perfectly acceptable to embed an expression in a print list.
Having said that, if the expression is long or complicated, I'd usually move it out of the print statement.
$fo ||= 'Roses are red ...';
print "My homework: $fo";
As others have already pointed out, a FALSE value can be "non empty",
so || is probably not the best choice.
# (fo will be updated with a real value in this part)
You'll need to tell us what's going on there.
My first guess was that you're perhaps doing something like:
$ perl -E '
my $fo = "";
update($fo);
print "|$fo|";
sub update {
my ($arg) = @_;
$arg .= "XXX";
}
'
||
when what you really wanted was something like:
$ perl -E '
my $fo = "";
update(\$fo);
print "|$fo|";
sub update {
my ($arg) = @_;
$$arg .= "XXX";
}
'
|XXX|
But there would be dozens of reasons why your update could be returning a "forrible" value. :-)
| [reply] [d/l] [select] |
|
... a FALSE value can be "non empty", so || is probably not the
best choice.
I don't understand this statement. (Update: hippo has likely shown the
way to understanding. :) Is there any false value of
$x, empty or not, for which the expression ($x || $y)
would not evaluate as the value of $y? Likewise, given the
statement
$x ||= $y;
is there any false initial value of $x for which the final
value of $x would not end up as $y?
Give a man a fish: <%-{-{-{-<
| [reply] [d/l] [select] |
|
$x = 0;
$y = 10;
$number = $x || $y;
print "$number\n";
You would see 10 rather than the valid-but-false 0. In such cases $number = $x // $y; might be more appropriate.
| [reply] [d/l] [select] |
|
Pretty much what ++hippo said. :-)
length will return FALSE for both '' and undef,
and TRUE for both 0 and '0'.
It's first documented as doing that in 5.12.0;
however, there was a bug that was fixed in 5.14.0
(perl5140delta: Syntax/Parsing Bugs)
so I'd be more comfortable with both defined and length
if using anything earlier than 5.14.0.
# 5.14.0 or later
$ perl -E 'my ($x, $y) = (0, "fallback"); $x = length $x ? $x : $y; sa
+y $x'
0
$ perl -E 'my ($x, $y) = ("0", "fallback"); $x = length $x ? $x : $y;
+say $x'
0
$ perl -E 'my ($x, $y) = ("", "fallback"); $x = length $x ? $x : $y; s
+ay $x'
fallback
$ perl -E 'my ($x, $y) = (undef, "fallback"); $x = length $x ? $x : $y
+; say $x'
fallback
# 5.12.0 or earlier
$ perl -E 'my ($x, $y) = (0, "fallback"); $x = (defined $x && length $
+x) ? $x : $y; say $x'
0
$ perl -E 'my ($x, $y) = ("0", "fallback"); $x = (defined $x && length
+ $x) ? $x : $y; say $x'
0
$ perl -E 'my ($x, $y) = ("", "fallback"); $x = (defined $x && length
+$x) ? $x : $y; say $x'
fallback
$ perl -E 'my ($x, $y) = (undef, "fallback"); $x = (defined $x && leng
+th $x) ? $x : $y; say $x'
fallback
# Probably not what was intended
$ perl -E 'my ($x, $y) = ("0", "fallback"); $x ||= $y; say $x'
fallback
$ perl -E 'my ($x, $y) = ("", "fallback"); $x //= $y; say "<$x>"'
<>
| [reply] [d/l] [select] |
Re: conditional print. Is correct to use it?
by jcb (Parson) on Oct 28, 2020 at 02:12 UTC
|
I typically initialize variables explicitly to undef (as in my $var = undef;) if I cannot produce a meaningful initial value at that point in the program. If this is done, then the test to later determine if a value was produced is simply defined($var) and usually producing an undefined value is just as bad as producing no value, so die "..." unless defined($var); works well to bail out on error later.
And just a reminder, you are including use strict; and use warnings;, right?
| [reply] [d/l] [select] |
|
| [reply] |