in reply to Warnings on unused variables?

There is such a warning ("once") for package variables

>perl -c -we"print $a" Name "main::a" used only once: possible typo at -e line 1.

On the p5p list, there was talk of doing something similar for lexical variables. It's a very long thread, so what follows is a highlight.

First, it seems there's no real good reason. Quote demerphq,

Used once warnings are irritating and IMO unnecessary for lexicals.

The reason globals have the warning is that it is easy to make a typo that changes program behaviour without being notified of it any other way.

$Foo::Baar=1; print "Foo::Bar is enabled" if $Foo::Bar;

Strictures will not catch this, in fact, nothing but "used once" errors will catch this.

However notice that under strictures its impossible to construct the same scenario with lexicals as one of the two usages will be an undeclared variable error.

Furthermore, it seems there are too many legit uses of single-use lexical variables to add a warning. Some examples from the thread:

my $foo = 42; eval q[$foo++];
my($unused, $foo) = func();
{ open my $fh, ">$file" or die $! } # touch
{ my $lock = lock_something(); # lock released on scope exit do_stuff_that_needs_the_lock(); }
{ my $tree = ...; my $sentry = Object::Destroyer->new( $tree, 'delete' ); ... }
my $object = bless \do {my $var} => $class;

Due to all the false positives, it seems the general consensus is that the check should done by a linter (e.g. Perl::Critic).

Replies are listed 'Best First'.
Re^2: Warnings on unused variables?
by AZed (Monk) on Sep 27, 2008 at 13:42 UTC

    Mhm, thanks for the explanation, though I would not have considered cases 2, 3 or 6 false positives (those are the kinds of things I would want to catch, honestly), and would not have considered 1, 4 and 5 single-use (#1 uses $foo++, #4 in theory will see $lock checked at least once inside do_stuff_that_needs_the_lock(), and #5 passes $tree to new()).

    Anyway, I took Grinder's point that use warnings::unused could be left commented out for commits, and went with that. It's Worked For Me™ so far.

    Thanks, all.

      I would not have considered cases 2, 3 or 6 false positives

      Why not? A warning would be issued for complete, accurate, functioning code. That's the very definition of a false positive.

      #2 ignores one of the function's return values. There are other ways of doing it, but there's nothing wrong with that way.

      #3 implements creates an empty file.

      #6 is used in creating inside out objects.

      #1 uses $foo++

      No. As far as Perl is concerned, '$foo++' might as well be 'print "Hello World"' when the program is compiled. $foo is only seen long after the warning has been issued, when the eval is executed.

      #4 in theory will see $lock checked at least once inside do_stuff_that_needs_the_lock()

      No. It's not passed to do_stuff_that_needs_the_lock (which would be using it twice).

      #5 passes $tree to new()

      Yeah, but what about $sentinel?

      #4 and #5 are both examples of Resource Acquisition Is Initialization objects where the functionality exists solely in the constructor and the (implicitly called) destructor.

        Mhm, either you and I have different definitions of 'accurate', or we have different conceptions about what constitutes a useful warning. I want warnings on code that, especially if handed to someone who didn't write it, is more likely than equivalent code that doesn't generate the warning to become the seed of a future bug. To me, a warning says, "Okay, well, yes, you can technically do it that way, but it's likely to be better in the long run if you do something else."

        Specifics follow the jump.

Re^2: Warnings on unused variables?
by Animator (Hermit) on Sep 28, 2008 at 12:46 UTC

    Another case that is missing is when functions are called via a dispatch table and are passed a list of variables. (Which the function may or may not need.)

    In the current code base at work each functions recieves 5 common arguments. Some will use all of them, others only one.

      I'm a little confused here... why would that trigger an unused warning? The variables in the calling code will be used, and the receiving function will be declaring its own, assigning out of @_, and discarding the rest, so it shouldn't have a problem either.

      Could you post an example?

        For example:

        sub foo1 { my ($c, $d, $e, $f) = @_; return $d * f; } sub foo2 { my ($c, $d, $e, $f) = @_; return $c + $d + $e + $f; } sub do_foo { my $which = $_[0] ? \&foo1, \&foo2; $which->(1, 2, 3, 4); }

        As you see foo1 uses only uses the second argument and fourth ($d, $f). But the assignment happens via my ($c, $d, $e, $f) = @_;. If a warnings is introduced for lexical variables that are used once then it will warn. (lexicals $c and $e are declared and initialized but never used.

        Yes, the assignment could be changed into: my ($d, $f) = @_[1, 3]; but this would be worse from a maintenance point of view.

        With my ($c, $d, $e, $f) = @_; you know exactly what parameters are passed (assuming they get a decent name). If you use my ($d, $f) = @_[1, 3]; then you are clueless about the other arguments.
        If you later need the other arguments then you need to start looking in what order they were passed.

      It wasn't meant to be an exhaustive list. They were the examples other people wrote in the P5P list thread.