[Melbourne-pm] Closures and scope warnings
Damian Conway
damian at conway.org
Tue Jul 27 21:01:09 PDT 2010
Jacinta observed:
> Would you *really* want every subroutine which creates variables which
> shadow top-level variables to warn about such? I don't think Perl
> distinguishes between your case and mine.
It doesn't even distinguish this case:
my $name = "Jacinta";
{
my $name = 'shift';
print "$name\n";
}
The whole point of lexical scope is that variables declared inside a
block hide identically named variables declared outside the block. It
doesn't matter if the block is "raw" (as above) or is the body of a
named subroutine (like Jacinta's example), or the body of an unnamed sub
(like Toby's example).
Of course, it is annoying if you're using an upscope variable within a
closure and you accidentally shadow it with a lexical declaration. I use
closures all the time, so I have a couple of techniques that make that
mistake very unlikely.
If the upscope variable is being used only as a value, I generally
capitalize its name. For example:
sub generate_prompter {
my ($PROMPT) = @_;
return sub {
print $PROMPT;
return readline;
}
}
The capitals help me remember to treat it as a constant, and stop
it from shadowing any in-scope lexicals (because they'll have
lowercase names, like variables normally do).
If the upscope variable is being modified downscope, I generally
name it $outer_whatever or $shared_whatever. For example:
my $shared_verbose;
sub set_verbose {
my $verbose = shift // 1;
$shared_verbose = $verbose;
}
sub get_verbose {
return $shared_verbose;
}
The longer name helps prevent name collisions with in-scope lexicals,
which generally get shorter names.
Thus, I'd write Toby's example something like:
sub do_something {
my $schema; #isa DBIx::Class::Schema
my $user = $schema->resultset('Users')->find(1);
my $NEW_ROLE = "something";
my $outer_old_role;
$schema->txn_do(sub {
$user->name("flooble");
$outer_old_role = $user->role; # <-- accessing data outside
$user->add_role($NEW_ROLE); # <-- and again
$user->update;
});
}
It's not fool-proof, but this approach does reduce the chance of name
collisions significantly. Of course, there's no reason to adopt my
particular naming scheme, but having *some* consistent naming scheme
for these situations really is a good idea.
Damian
More information about the Melbourne-pm
mailing list