[Melbourne-pm] Closures and scope warnings

Scott Penrose scottp at dd.com.au
Tue Jul 27 21:13:42 PDT 2010


Dooh... Damian is right, I didn't actually test my code, and have made assumptions... probably for years :-)

So... the rule is that warnings only happen within the same level of block?

Scott


----- Original Message -----
> 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
> _______________________________________________ Melbourne-pm mailing
> list Melbourne-pm at pm.org
> http://mail.pm.org/mailman/listinfo/melbourne-pm

-- 
http://scott.dd.com.au/
scottp at dd.com.au




More information about the Melbourne-pm mailing list