How can I locate unused variables and/or dead code in Perl? This can easily be done in Java with an IDE. Can it be done in Perl?
This is a single stand-alone script and I will spot any variables that might be used in one of the requires.
Perl::Critic is a comprehensive package for source-code standards checking. It's capable of finding unused variables and unreachable code among many other things.
See warnings::unused.
This pragmatic module extends lexical warnings to complain about unused variables.
It produces warnings when a my variable or state variable is unused aside from its declaration.
Related
Here is my system configuration.
Perl-Epic 0.7.8
Strawberry Perl 5.32.1 64 bit.
PadWalker 2.5 installed with Strawberry perl
Here is what I have already read.
http://www.epic-ide.org/faq.php#debug
In my case, the message "perl5db.pl did not return a true value." is not displayed in the console. Also the bug report mentioned in that FAQ has been resolved so I would think that things should be working on the latest windows version of Perl by now. Also that issue appears to be related to a win32 specific subroutine that doesn't exist in my perl installation since it is a win64 install.
https://sourceforge.net/p/e-p-i-c/bugs/711/
This might be related, but not sure. My program which only involves two variables follows.
Unable to view locals in Eclipse + EPIC
I do tried the latest stable and testing versions of EPIC. Both produced the same result.
Here is a simple test program.
#!/usr/bin/perl
$a = 1;
$b=2;
print($a+$b);
[
Update
If I declare the variables explicitly then they show in the debugger. Within one of the other threads I noticed that the asker did not declare using the my keyword either. That is an opportunity for someone to answer with a confirmation of whether this is how PadWalker works. The documentation for it mentions that it works on lexical variables which are in scope. I'm new to Perl programming and learning it due to scripts that I have to learn to maintain so I am unsure if my interpretation of the documentation is correct. However, I think that is the answer that the variables must be declared so that each has a scope. Please advise.
The answer appears to lie in the module documentation for PadWalker which states, "PadWalker is a module which allows you to inspect (and even change!) lexical variables in any subroutine which called you. It will only show those variables which are in scope at the point of the call." The key point is that declaring the variable with the my keyword is what causes the variable to be declared with scope.
Moreover, the PERL-EPIC documentation for Eclipse indicates that it relies on PadWalker to provide a debug capability. Therefore the ability to inspect variables in the Eclipse debugger using that specific plugin depends on explicitly declaring variables.
You can see in the image here that the variables show up when declared.
I am writing a perl script that needs to set a number of environment variables before calling an external program. My code has the form
$ENV{'VAR1'} = "value1";
$ENV{'VAR2'} = "value2";
When running this through perlcritic, I get a severity 4 violation for every such assignement:
^Magic variable "$ENV" should be assigned as "local"
Googling that error message didn't give me any good solutions. The perlcritic violation that complains in that case is Variables::RequireLocalizedPunctuationVars, and the example given deals with localizing a file handle. I tried to find the relevant section in Perl Best Practices, but it only talks about localizing package variables.
One solution I tried is to localize %ENV using the following statement before the assignments.
local %ENV = ();
This doesn't resolve the violation.
My question is the following:
Is that Perlcritic violation even relevant for assignments to %ENV, or can I ignore it?
If it's relevant, what's the best way to resolve it?
Perlcritic warnings are not The Word of God. They are simply warnings about situations that, if managed incorrectly, could get you into trouble.
Is that Perlcritic violation even relevant for assignments to %ENV, or
can I ignore it?
This warning tells you that:
Global Variables have the very real possibility of action at a distance.
This possibility is even more dangerous when dealing with those variables that change the operation of built in functions.
Is that relevant for %ENV? If you spawn more than one child process in your program, Yes. If someone changes your program later to spawn another child, Yes.
If it's relevant, what's the best way to resolve it?
Now here is where being the human being becomes important. You need to make a value judgement.
Possible actions:
Ignore the warning and hope that future maintainers aren't bitten by your usage of this Global Variable.
Change your code to avoid the situation you are being warned about. The syntax suggested by choroba is a fine option.
Now if you have made a change, are still getting the warning, and believe that the warning is now in error, you can do one or more of:
Be a good citizen and Submit a bug report.
use the comment ## no critic (RequireLocalizedPunctuationVars) on the affected lines or on it's own line before the lines in question.
Or more excessively disable the rule or just create an exception for %ENV in your .perlcriticrc file.
You can localize the value for the given environment variable only:
local $ENV{VAR1} = 'value1';
Consider using Env. perlcritic does not complain about the variable:
use warnings;
use strict;
use Env qw(VAR);
$VAR = "value1";
I have a set of 3 or 4 separate Perl scripts that used to be part of a simple pipeline, but I am now trying to combine them in a single script for easier use (for now without subroutine functions). The thing is that several variables with the same name are defined in the different scripts. The workaround I found was to give different names to those variables, but it can start to become messy and probably it is not the correct way of doing so.
I know the concept of global and local variables but I do not quite understand how do they exactly work.
Are there any rules of thumb for dealing with this sort of variables? Do you know any good documentation that can shed some light on variable-scope or have any advise on this?
Thanks.
EDITED: I already use "use warnings; use strict;" and declare variables with "my". The question might actually be more related to the definition of scoping blocks and how to get them to be independent from each other...
You are likely getting into trouble because of your use of global variables (which actually likely exist in package main). You should try to avoid the use of global variables.
And to do so, you should become familiar with the meaning of variable scope. Although somewhat dated, Coping with Scoping offers a good introduction to this topic. Also see this answer and the others to the question How to properly use Global variables in perl. (Short Answer: avoid them to the degree possible.)
The principle of variable scope and limiting use of global variables actually applies to nearly all programming languages. You should get in the habit of declaring variables as close as possible to the point where you are actually using them.
And finally, to save yourself from a lot of headaches, get in the habit of:
including use strict; and use warnings; at the top every Perl source file, and
declaring variables with my within each of your sub's (to limit the scope of those variables to the sub).
(See this PerlMonks article for more on this recommendation.)
I refer to this practice as "Perl programming with your seat belt on." :-)
The rule of thumb is to put your code in subroutines, each of them focused on a simple, well-defined part of the larger process. From this one decision flow many virtuous outcomes, including a natural solution to the variable scoping problem you asked about.
sub foo {
my $x = 99;
...
}
sub bar {
my $x = 1234; # Won't interfere with foo's $x.
...
}
If, for some reason, you really don't want to do that, you can wrap each section of the code in scoping blocks, and make sure you declare all variables with my (you should be doing the latter nearly always as a matter of common practice):
{
my $x = 99;
...
}
{
my $x = 1234; # Won't interfere with the other $x.
...
}
It is stated in section "Global variables and constants" of the Google Common Lisp Style Guide that:
"Common Lisp does not have global lexical variables, so a naming convention is used to ensure that globals, which are dynamically bound, never have names that overlap with local variables.
It is possible to fake global lexical variables with a differently named global variable and a DEFINE-SYMBOL-MACRO. You should not use this trick, unless you first publish a library that abstracts it away."
Can someone, please, help me to understand the meaning of this last sentence.
The last sentence,
You should not use this trick, unless you first publish a library that abstracts it away.
means that if you do something that simulates global lexical variables, then the implementation of that simulation should not be apparent to the user. For instance, you might simulate a global lexical using some scheme using define-symbol-macro, but if you do, it should be transparent to the user. See Ron Garret's GLOBALS — Global Variables Done Right for an example of “a library that abstracts it away.”
I need to import all our variables from the unnamed Perl module (Module.pm) and use them inside the Perl script (Script.pl).
The following code works well without the "use strict", but failed with it. How can I change this code to work with "use strict" without the manual listing of all imported variables (as described in the answer to other question)?
Thanks a lot for your help!
Script.pl:
use strict;
require Module;
print $Var1;
Module.pm:
our $Var1 = "1\n";
...
our $VarN = "N\n";
return 1;
Run the script:
$> perl Script.pl
Errors:
Global symbol "$Var1" requires explicit package name at Script.pl line 3.
Execution of Script.pl aborted due to compilation errors.
NOTE (1): The module is unnamed, so using a Module:: prefix is not the option.
NOTE (2): Module.pm contains also a set of functions configured by global variables.
NOTE (3): Variables are different and should NOT be stored in one array.
NOTE (4): Design is NOT good, but the question is not about the design. It's about forcing of the listed code to work with minimal modifications with the complexity O(1), i.e. a few lines of code that don't depend on the N.
Solution Candidate (ACCEPTED): Add $:: before all imported variables. It's compliant with strict and also allows to differ my variables from imported in the code.
Change your script to:
use strict;
require Module;
print $Module::Var1;
The problem is the $Var1 isn't in the main namespace, it's in Module's namespace.
Edit: As is pointed out in comments below, you haven't named your module (i.e. it doesn't say package Module; at the top). Because of this, there is no Module namespace. Changing your script to:
use strict;
require Module;
print $main::Var1;
...allows the script to correctly print out 1\n.
If you have to import all the our variables in every module, there's something seriously wrong with your design. I suggest that you redesign your program to separate the elements so there is a minimum of cross-talk between them. This is called decoupling.
You want to export all variables from a module, and you want to do it in such a way that you don't even know what you're exporting? Forget about use strict and use warnings because if you put them in your program, they'll just run screaming out, and curl up in a corner weeping hysterically.
I never, and I don't mean hardly ever, never export variables. I always create a method to pull out the required value. It gives me vital control over what I'm exposing to the outside world and it keeps the user's namespace pure.
Let's look at the possible problems with your idea.
You have no idea what is being exported in your module. How is the program that uses that module going to know what to use? Somewhere, you have to document that the variable $foo and #bar are available for use. If you have to do that, why not simply play it safe?
You have the issue of someone changing the module, and suddenly a new variable is being exported into the program using that module. Imagine if that variable was already in use. The program suddenly has a bug, and you'll never be able to figure it out.
You are exporting a variable in your module, and the developer decides to modify that variable, or even removes it from the program. Again, because you have no idea what is being imported or exported, there's no way of knowing why a bug suddenly appeared in the program.
As I mentioned, you have to know somewhere what is being used in your module that the program can use, so you have to document it anyway. If you're going to insist on importing variables, at least use the EXPORT_OK array and the Exporter module. That will help limit the damage. This way, your program can declare what variables its depending upon and your module can declare what variables it knows programs might be using. If I am modifying the module, I would be extra careful of any variable I see I am exporting. And, if you must specify in your program what variables you're importing, you know to be cautious about those particular variables.
Otherwise, why bother with modules? Why not simply go back to Perl 3.0 and use require instead of use and forget about using the package statement.
It sounds like you have data in a file and are trying to load that data into your program.
As it is now, the our declarations in the module only declare variables for the scope of that file. Once the file finshes running, to access the variables, you need to use their fully qualified name. If your module has a package xyz; line, then the fully qualified name is $xzy::Var1. If there is no package declaration, then the default package main is used, giving your variables the name $main::Var1
However, any time that you are making many variables all with numeric name changes, you probably should be using an array.
Change your module to something like:
#My::Module::Data = ("1\n", "2\n" ... )
and then access the items by index:
$My::Module::Data[1]