Re: Closure warning with Perl 5.14?
by BrowserUk (Patriarch) on May 19, 2011 at 08:36 UTC
|
my $color = shift if @_;
If you only pass 1 parameter to the outer sub, $color will never be declared, so won't (can't) be available to the inner sub.
If you just dropped the conditional, the code would work properly. If you shift a value from an empty array into a scalar it will be set to undef which will work fine in the inner sub conditional.
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
use warnings;
use strict;
my $x = <>;
my $y = "X" if $x =~ /X/;
$y = "Z" if !defined $y;
print "$y\n";
| [reply] [Watch: Dir/Any] [d/l] |
|
But shouldn't there be a warning in 5.12?
There should have been a warning for that in perl 5.0.
Shouldn't the warning be consistent in 5.14?
Variables declared in a conditional always was "undefined" behavior. To quote perlsyn:
NOTE: The behaviour of a "my" statement modified with a statement
modifier conditional or loop construct (e.g. "my $x if ...") is
undefined. The value of the "my" variable may be "undef", any
previously assigned value, or possibly anything else. Don't rely on
it. Future versions of perl might do something different from the
version of perl you try it out on. Here be dragons.
(emphasis mine). The perl-5.14.0 behavior (new warning) is consistent with the documentation, and a good thing.
| [reply] [Watch: Dir/Any] |
|
|
use warnings;
use strict;
my $x = <>;
my $y = "X" if $x =~ /X/;
sub x{
print $y ? 'Okay' : 'bad';
}
print "$y\n";
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] [Watch: Dir/Any] [d/l] |
|
|
|
But shouldn't there be a warning in 5.12?
It warns, but only if Perl can, at compile time, determine that the condition is false.
| [reply] [Watch: Dir/Any] |
|
|
|
|
Re: Closure warning with Perl 5.14?
by wind (Priest) on May 19, 2011 at 08:44 UTC
|
Remove the if after the declaration of $color. It serves no purpose and is leading to the error:
my $color = shift;
If you were ever to need initialize a variable conditionally, be sure to use the ternary operator
my $variable = $condition ? 'value' : undef;
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
Thanks. Yeah, that is the way to remove the warning.
The parameter is documented as optional, so I thought the code looked most obvious like that. I'll update my Best Practices.
| [reply] [Watch: Dir/Any] |
|
I'll update my Best Practices.
perlcritic detects this by default:
Variable declared in conditional statement at line , column . Declare
+ variables outside of the condition. (Severity: 5)
Perl::Critic::Policy::Variables::ProhibitConditionalDeclarations
| [reply] [Watch: Dir/Any] [d/l] |
|
By coincidence I have been having a similar problem in 5.8.2. When assigning a variable to a match backreference, at outer scope there was no warning when the match failed. When assigning it to a variable at level 1 loop scope from within a level 2 loop, it gave the warning that something was uninitialised in the match expression (an untrue statement). Furthermore, even using the ternary operator to force the variable to '' on match failure, the match warning was delayed until the variable was subsequently tested with a simple "if ($var)" at which point it made even less sense. I get the impression that Perl can sometimes catch its feet slightly when trying to process potential uninitialisation for variables being updated or initialised in a different lexical and sub-global scope from which they were declared.
| [reply] [Watch: Dir/Any] |
Re: Closure warning with Perl 5.14?
by ikegami (Patriarch) on May 19, 2011 at 09:50 UTC
|
use strict;
use warnings;
sub foo {
my ($x) = @_;
return sub { eval 'print "$x\n";' };
}
sub bar {
my ($x) = @_;
return sub { $x if 0; eval 'print "$x\n";' };
}
foo("foo")->();
bar("bar")->();
(Note: The if 0 just avoids a void context warning. Removing it doesn't change the outcome.)
That you also get it in 5.14 under some circumstances involving illegal code (my ... if ...;) is not a problem.
| [reply] [Watch: Dir/Any] [d/l] [select] |