perlpal has asked for the wisdom of the Perl Monks concerning the following question:

Hi, Please could i know how to identify unused and uninitialised variables from a perl script?Trying to clean up my code and am finding this task quite exhaustive. Thanks In Advance!
  • Comment on Identify Unused and Uninitialised variables.

Replies are listed 'Best First'.
Re: Identify Unused and Uninitialised variables.
by andreas1234567 (Vicar) on Jan 14, 2009 at 09:49 UTC
    Perl::Critic can help you find unused variables:
    $ cat foo.pl use strict; use warnings; my ($unused, $i, $j); $i = $j; # uninitialized __END__ $ perlcritic -3 foo.pl .. "$unused" is declared but not used. at line 4, column 1. Unused varia +bles clutter code and make it harder to read. (Severity: 3) ..
    I guess uninitialised variables only can be detected at run-time, but I can not think of an immediate solution apart from rigorous testing.

    (Output from perlcritic was edited for clarity).

    Update:

    print and some math functions will warn if it detects uninitialised variables (assuming warnings is enabled):

    $ perl -wle 'my $i; print $i' Use of uninitialized value in print at -e line 1. $ perl -wle 'my $i; $i += $i' Use of uninitialized value in addition (+) at -e line 1. $ perl -wle 'my $i; if ($i>0) {}' Use of uninitialized value in numeric gt (>) at -e line 1.
    However, you may not always want to print or do calculations on your variables.

    The warnings are described in perldiag:

    Use of uninitialized value%s

    (W uninitialized) An undefined value was used as if it were already defined. It was interpreted as a "" or a 0, but maybe it was a mistake. To suppress this warning assign a defined value to your variables.

    To help you figure out what was undefined, perl will try to tell you the name of the variable (if any) that was undefined. In some cases it cannot do this, so it also tells you what operation you used the undefined value in. Note, however, that perl optimizes your program and the operation displayed in the warning may not necessarily appear literally in your program. For example, "that $foo" is usually optimized into ""that " . $foo", and the warning will refer to the "concatenation (.)" operator, even though there is no "." in your program.

    --
    No matter how great and destructive your problems may seem now, remember, you've probably only seen the tip of them. [1]
      I can not reproduce your perlcritic output. Here is what I get (running on v5.8.8 built for x86_64-linux):
      $ cat foo.pl use strict; use warnings; my ($unused, $i, $j); $i = $j; # uninitialized __END__ $ perlcritic -3 foo.pl Code not contained in explicit package at line 1, column 1. Violates +encapsulation. (Severity: 4) Module does not end with "1;" at line 5, column 1. Must end with a re +cognizable true value. (Severity: 4) $ perlcritic -Version 1.080 $

      What version of perlcritic do you have? Perhaps mine is too old (1 year old), and I need to upgrade.

      Do you have a .perlcritic file? Maybe that has some tool configuration settings that I need to use. Now that you have shown me this cool capability, I really want to use it. Any help would be appreciated.

        I'm using
        $ perlcritic --version 1.090
        Do you see the warning if you use perlcritic -2 instead?

        Update the module, you are most likely 6 months behind. See the Changes file:

        1.088 Released on 2008-07-04

        * Due to the consensus at YAPC::NA 2008, Variables::ProhibitUnusedVariables default severity has been raised to medium/3.

        --
        No matter how great and destructive your problems may seem now, remember, you've probably only seen the tip of them. [1]
Re: Identify Unused and Uninitialised variables.
by Skeeve (Parson) on Jan 14, 2009 at 09:32 UTC

    Always

    use strict; use warnings;

    That will help a lot!


    s$$([},&%#}/&/]+}%&{})*;#$&&s&&$^X.($'^"%]=\&(|?*{%
    +.+=%;.#_}\&"^"-+%*).}%:##%}={~=~:.")&e&&s""`$''`"e
      Pray tell me, how's "use strict" going to help you here? In fact, it may even be harder to find unused variables when using "use strict", as "use strict" usually means people will use lexical variables instead of package variables.

      But, with warnings on, Perl will warn about unused (or used only once) variables, while it will remain silent about unused lexicals.

Re: Identify Unused and Uninitialised variables.
by holli (Abbot) on Jan 14, 2009 at 09:36 UTC
    Maybe using some editor-fu, like
    • search and replace all "my"s with "#my"
    • run your code and see the errors
    • put the "my"s back in where it complains
    • once the code compiles again, all "#my" that are left are unused
    You do run under strict, right? :)


    holli, /regexed monk/
      Unfortunally, that may mean that the following code:
      sub foo { my $i; for $i (...) { ... if (...) { my $i; $i = something; ... } } }
      may end up as:
      sub foo { my $i; for $i (...) { ... if (...) { # my $i; $i = something; ... } } }
      However, the inner '$i' certainly wasn't an unused variable.

        You are right. You are absolutely right.

        Any code written like that could have unintended bugs but they will learn a valuable lesson in proper variable naming conventions at the same time.

Re: Identify Unused and Uninitialised variables.
by toolic (Bishop) on Jan 14, 2009 at 13:53 UTC
Re: Identify Unused and Uninitialised variables.
by CountZero (Bishop) on Jan 14, 2009 at 10:23 UTC
    What do you mean by uninitialised?

    Are my $scalar; or my @array uninitialised? or are my $scalar =''; or my @array = () ?

    And what about my @array = (); print $array[0];? Does every element in the array need to have some defined value to be considered initialised?

    What about a hash that has keys but all values are undef? It would probably get even worse to solve if one thinks about objects or complicated structures of variables built through references.

    A static analysis of the perl-code cannot find all cases of uninitialised variables.

    And then, are uninitialised variables a "bad thing" per se? I doubt it.

    CountZero

    A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

      I think the op may have been thinking of "useless variables" as mentioned in your sig. I often go back over my code and find that as it developed uncessary variables (even subs and objects) are left hanging around.

      One way of reducing this is to declare vars as close too where the vars are used as you can, and in the smallest scope possible. Even to the extent of creating a scope to put them in. When reviewing/refactoring you can see that the whole block (with its vars) can come out.

      my $html; { # $filename and $fh only used here # and they won't conflict with anything else my $filename = q{some/file.html}; open my $fh, q{<}, $filename or die qq{cant open $filename: $!\n}; $html = do{local $/;<$fh>}; } # any previous $filename and $fh remain unharmed
      To be more precise, i meant useless variables which are there in the script but bot being used. They may or maynot be initialized.
Re: Identify Unused and Uninitialised variables.
by swampyankee (Parson) on Jan 14, 2009 at 18:03 UTC

    I don't think that there is a tool to do that; using strict and warning will help find variables which aren't declared, but won't find variables that are declared but not used. The walksymboltable routine in B may permit you to do that, but it may be more trouble than it's worth. Devel::Refactor may also help, in that its refactored code may have unused variables removed.


    Information about American English usage here and here. Floating point issues? Please read this before posting. — emc