Search code examples
perlexporter

imported perl variable imports with no value


SOLVED: As it turns out, my problem was rooted in the fact that I was not putting a $ in front of DEBUGVAR in the @EXPORT_OK assignment and the "use config_global qw(config DEBUGVAR);" line. Since it raises no error, I had no way to know this was the issue. So, the fix is to place the proper syntax in front of your variables at these points.

So I am trying to get the hang of writing and importing perl modules. I don't know why it was made so difficult to do this, but I am having a great deal of trouble with this seeimingly trivial task. Here is the contents of my module:

package global_config;
use strict;

require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(DEBUGVAR);

our ($DEBUGVAR);

our $DEBUGVAR = "Hello, World!";

return 1;

Here are the contents of my perl script that imports the module:

use strict;

use config_global qw(config, DEBUGVAR);
our %config;
our $DEBUGVAR;


print "variable imported with value: ".$DEBUGVAR;

The output is "variable imported with value:", and nothing else. My variable appears to be losing it's value. What am I doing wrong?

EDIT: After fiddling around a bit, and turning warnings on, I have isolated the issue to being that $DEBUGVAR is never actually imported. When I use it via $config_global:DEBUGVAR, it works as expected. The issue now is that it is not importing into the namespace. What gives?


Solution

  • I see several issues:

    • You should not use a comma in the qw() syntax. The qw takes each whitespace separated phrase and puts it in an array element.

    These two are the same:

    my @bar = qw(foo bar barfu);          #No commas!
    my @bar = ("foo", "bar", "barfu");    #Commas Required
    
    • If you're exporting a variable, you need to put the sigil in front of it.

    You have:

    our @EXPORT_OK = qw(DEBUGVAR);
    

    It should be:

    our @EXPORT_OK = qw($DEBUGVAR);
    
    • You should use the newer Exporter syntax:

    Here's the newer Exporter Syntax:

    package global_config;
    use strict;
    use warnings;
    
    use Exporter 'import';   #Not "require". No need for "@ISA"
    
    our @EXPORT_OK = qw(DEBUGVAR);
    
    our $DEBUGVAR = "Hello, World";
    
    1;    #Makes no real difference, but you shouldn't say "return 1". Just standard.
    
    • Finally, what are you doing exporting variables? That's just a bad practice.
      • Exporting anything is now questioned -- even functions. It pollutes the user's namespace. (At least you're using @EXPORT_OKAY). Take a look at File::Spec. It uses fully qualified package names for its subroutines by default.
      • The variable in question is accessible via the full package name $global_config::DEBUGVAR, so there's no real need to export it.
      • What if everybody did it? Yes, you last heard of this excuse in kindergarten, but it applies here. Imagine if several modules exported $DEBUGVAR.

    There are several ways around your quandary, but the best is to use object oriented Perl to help set this variable, and even allow users to change it.

    package MyPackage;
    
    use strict;
    use warnings;
    use feature qw(say);
    
    sub new {
       my $class = shift;
       my $debug = shift;  #Optional Debug Value
    
       my $self = {};
       bless $self, $class;
    
       if (not defined $debug) {
          $debug = "Hello, world!";
    
       $self->Debug($debug);
       return $self;
    }
    
    sub Debug {
       my $self  = shift;
       my $debug = shift;
    
       if (defined $debug) {
          $self->{DEBUG} = $debug;
       }
       return $debug;
    }
    
    1;
    

    To use this module, I simply create a new object, and Debug will be set for me:

    use strict;
    use warnings;
    use MyPackage               #No exporting needed
    
    #Create an object w/ Debug value;
    my $obj = MyPackage->new;   #Debug is the default.
    say $obj->Debug;            #Prints "Hello, world!"
    
    # Change the value of Debug
    $obj->Debug("Foo!");
    say $obj->Debug;            #Now prints "Foo!"
    
    #Create a new object with a different default debug
    $obj2 = MyPackage->new("Bar!");
    say $obj2->Debug;           #Print "Bar!";
    

    This solves several issues:

    • It allows multiple values of debug because each object now has its own values
    • There is no worry about namespace pollution or accessing package variables. Again, all you need is contained in the object itself.
    • It's easier to debug issues since the complexity is hidden inside the objects themselves.
    • It's the new preferred method, so you might as well get use to the syntax and be able to read object oriented Perl code. You'll be seeing it more and more.