Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to import all "our"-variables from the unnamed Perl module without listing them?

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.

like image 790
linuxbuild Avatar asked Sep 12 '11 17:09

linuxbuild


3 Answers

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.

  1. 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?
  2. 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.
  3. 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.

like image 56
David W. Avatar answered Oct 19 '22 22:10

David W.


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.

like image 36
CanSpice Avatar answered Oct 19 '22 23:10

CanSpice


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.

like image 27
shawnhcorey Avatar answered Oct 19 '22 22:10

shawnhcorey