http://qs1969.pair.com?node_id=439989

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

Hi Monks,

I'm trying to converting a script into a package using Exporter and my namespace seems to be getting poluted and I'm not sure why. An example that shows the issue...

Script
#!/usr/bin/perl use strict; use warnings; use mymodule; my $m = mymodule->new(); print "My Test\n"; $m->Func1(); $m->Func2("Fluffy", 5);
Module
package mymodule; require Exporter; use strict; use warnings; our @ISA = qw (Exporter); our @EXPORT = qw(); our @EXPORT_OK qw(Func1); our $VERSION = 0.01; sub new { my $class = shift; my $self = {}; bless ($self, $class); return $self; } sub Func1 { print "Hi there\n"; } sub Func2 { my ($class, $name, $value) = @_; print "hi $name, value $value\n"; }
Gives the following output...
My Test Hi there hi Fluffy, value 5

I've read as many of the related posts and articles I can find on the subject and using the Exporter module is what I want as it is supposed isolate the exposed subroutines and variables through the EXPORT and EXPORT_OK methods. From what I can tell the above code 'should' only run Func1 as it is registered as an external method with EXPORT_OK, however Func2 is not. I'm guessing this means I should get some sort of error saying that Func2 is not a member of the mymodule class/module, but it doesn't, it runs it why? ...and how can I prevent it as it seems to be allowing everything into the calling script's namespace?


Regards Paul.

Replies are listed 'Best First'.
Re: Writing Modules/namespace polution
by dragonchild (Archbishop) on Mar 16, 2005 at 15:53 UTC
    You're confusing exporting with object-oriented programming. You don't need Exporter to have an object, which is what you have. Change your script to:
    #!/usr/bin/perl use strict; use warnings; use mymodule; my $m = mymodule->new(); print "My Test\n"; $m->Func1(); $m->Func2("Fluffy", 5); Func1(); Func2("Fluffy", 5); sub Func1 { print "Func1() in main!\n" } sub Func2 { print "I'm still in main! (@_)\n" }

    See what happens?

    Being right, does not endow the right to be rude; politeness costs nothing.
    Being unknowing, is not the same as being stupid.
    Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence.
    Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.

      The little light goes on =).... Thanks...I'm trying to do a OO method, but I didn't realize the object had all the methods by default, which makes sense as they are essentially protected by virtue of the fact that you have to use the object.
        they are essentially protected by virtue of the fact that you have to use the object

        I would be careful about calling much in Perl protected. Sure, general politeness will keep most people from using the package in unintended ways, but Perl sure won't:

        Module

        package Example::Module; use strict; sub new { bless {}, shift } sub foo { my ($s, $v1, $v2) = @_; print "Hi '$v1' and '$v2'\n"; } 1;

        Script

        use strict; use Example::Module; # add a new sub to the package sub Example::Module::bar { my ($s, $v1, $v2) = @_; print "Bye '$v1' and '$v2'\n"; } my $em = Example::Module->new; $em->bar("one", "two"); # call the sub not as a method Example::Module::foo('one', 'two', 'three'); # change the existing sub *Example::Module::foo = sub { my ($s, $v1, $v2) = @_; print "Oops '$v1' and '$v2'\n"; }; $em->foo("one", "two");
Re: Writing Modules/namespace polution
by ikegami (Patriarch) on Mar 16, 2005 at 15:58 UTC

    Your name space isn't poluted:

    use strict; use warnings; use mymodule; print "My Test\n"; Func1(); # ERROR! Func2("Fluffy", 5); # ERROR!

    But check this out:

    use strict; use warnings; use mymodule qw( Func1 ); # Import Func1 #use mymodule qw( Func2 ); # This won't work since # Func2 is not in @EXPORT_OK. print "My Test\n"; Func1(); Func2("Fluffy", 5); # ERROR!

    You should never export methods. As you can see, there's no reason to do so. All functions in a package are tied to the object blessed to that package, whether you use Exporter or not.

    and how can I prevent it as it seems to be allowing everything into the calling script's namespace?

    It's possible to disguise a function using lexicals and/or closures so that noone outside the package can call it, but there's no need to do so. Write proper documentation instead.

      Thanks ikegami,
      I can see how the exporter is supposed to work now. I read so much on making modules and looking at what other people had done, I just ended up combining both ideas which was wrong.
      Regards Paul.
Re: Writing Modules/namespace polution
by tlm (Prior) on Mar 17, 2005 at 01:39 UTC

    Study the following short program and its output:

    use strict; sub Foo::bar { print 'called on line ', (caller)[2], ": $_[0]\n" and $_[0]; } my $frobozz = bless \&Foo::bar, 'Foo'; $frobozz->bar('eenie'); $frobozz->bar('eenie')->('meenie'); $frobozz->('eenie'); Foo->bar('eenie'); Foo->bar('eenie')->bar('meenie'); Foo::bar('eenie'); 'Foo'->bar('eenie'); 'Foo::bar'->('eenie'); "Foo'bar"->('eenie'); # Perl trivia # bar('eenie'); # bombs! require Exporter; @Foo::ISA = ('Exporter'); @Foo::EXPORT_OK = ('bar'); Foo->import('bar'); bar('eenie'); __END__
    Make sure you understand why each output line is generated (except the one corresponding to the code line marked as "Perl trivia"--that one's optional), and why un-commenting out the line that begins with # bar causes a run-time error. If, after you work through it, something still doesn't make sense, ask.

    Note! The above is certainly not an example of good coding. Its only purpose is to illustrate some aspects of Perl.

    the lowliest monk

Re: Writing Modules/namespace polution
by chas (Priest) on Mar 16, 2005 at 16:03 UTC
    Actually, the default exports should be in @EXPORT, not @EXPORT_OK. The only thing I notice immediately is that I believe you should "use Exporter" not "require Exporter" in the module file (Update: plus the other posted comments...)
    chas
      Notwithstanding the fact that he doesn't appear to need to export anything -- as pointed out by other posts -- I'm not so sure it's advisable to suggest using @EXPORT very often. I realize a lot of well known and good modules do this, but most of the time, I think it makes more sense to use @EXPORT_OK and let the caller specify what they want to import.
        Agreed, but aside from the object/non-object mixup which I didn't catch, I interpreted the original poster's comments as indicating that he expected use mymodule; would make the entries in @EXPORT_OK available without explicit package referencing. My misunderstanding, I guess...
        chas
      No, require is fine.
      I believe you should "use Exporter" not "require Exporter"

      I believe you should "require Exporter" or "use base 'Exporter'" not "use Exporter".

      The exporter module defines &Exporter::import so that it can be inheritied by other modules. Calling Exporter::import('Exporter') doesn't really make sense.

        Doing a "use Exporter;" will not do anything different than a "require Exporter;" because the import() function in Exporter doesn't do anything because Exporter doesn't define @EXPORT or @EXPORT_OK.

        The only difference between "use base Exporter;" and either "use Exporter;" or "require Exporter;" is that "use base" will modify @ISA for you and the others make you modify it yourself. You either have to have Exporter in your @ISA or have done something like *import = \&Exporter::import; to get the benefits of Exporter.

        Nothing more, nothing less.

        Being right, does not endow the right to be rude; politeness costs nothing.
        Being unknowing, is not the same as being stupid.
        Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence.
        Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.

        Well, I just checked in the Camel books. The 3rd edition does indicate "require Exporter;" in modules, but the 2nd edition (which I learned from) has "use Exporter;" in modules in most of the examples (although there was a "require Exporter;" in an example.) Randal Schwartz's book "Learning Perl Objects, References & Modules" says "...As a module author, all you do is add:
        use Exporter; our @ISA = qw(Exporter);
        I just made a module skeleton using h2xs, and "require Exporter;" appears in the module file. So maybe either will suffice..I'll go with the "require" form since that's what h2xs produced.
        chas
        (Update: Hadn't seen Dragonchild's reply yet - that seems to settle the difference. Fixed typo.)