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

I'd like to know how in a module to tell if a function foo has been exported (when it isn't exported by default). That is,

use ThisModule qw(foo);

How in ThisModule can I tell that foo is being exported.

The real reason is that foo requires a bit of initialization, and I don't want to do this unless necessary.

I could do something like:

{ my $value = undef; sub foo { unless (defined $value) { # initialize $value here } # do foo stuff using $value here } }

I believe this isn't Apache mod_perl-friendly. (Or am I wrong?)

Suggestions to answer both problems (how to tell if a function is exported from within a module, and the best way to initialize a variable the first time a function is called) would be helpful.

Replies are listed 'Best First'.
Re: How to tell if a sub has been exported?
by suaveant (Parson) on Oct 05, 2001 at 07:28 UTC
    I believe a better way to do this is to write your own import method, and catch what it is called with... for instance...
    use FOO qw(bar); bar();
    And in FOO.pm
    package FOO; use base Exporter; our @EXPORT_OK = qw(bar); sub import { print "Exporting the following from @_\n"; FOO->export_to_level(1, @_); } sub bar { print "Hello world\n"; } 1;
    Exporter gives you the export_to_level method to allow you to override import like this. Now you can examine the list import is called with at compile time and set things up accoringly.

    Realize, of course, that bar can be called without being exported, using FOO::bar()... you probably should do something along the lines of initializing if it is exported, and initializing it on the first call if it is called without being initialized properly. You can do tricks with AUTOLOAD and the like that can be fun :)

                    - Ant
                    - Some of my best work - Fish Dinner

Re (tilly) 1: How to tell if a sub has been exported?
by tilly (Archbishop) on Oct 05, 2001 at 07:31 UTC
    You could write a custom import. You could have an import that wraps around the usual Exporter with an appropriate goto to fool it into exporting to the right package. You could use the trick that Carp uses internally to handle "verbose" (namely having a failure to export method).

    But while all of those answer the asked question, I think that the best two solutions are either:

    my $foo_is_init; sub foo { $foo_is_init = init_foo() unless $foo_is_init; # etc }
    or else just don't have a foo and have an AUTOLOAD method which will lazily create and initialize foo. (ie Don't have your hook on exporting, have it on the first call to the function.)
Re: How to tell if a sub has been exported?
by miyagawa (Chaplain) on Oct 05, 2001 at 06:18 UTC
    It's not complete but would be suffice for many cases.
    package Foo; sub foo { my $pkg = caller; if ($pkg ne __PACKAGE__ && defined &{$pkg."::foo"}) { # exported } else { # not } }
    About another question, making variable init as a closure is well-known idiom (see Ima::DBI which makes DB connection as a clusure) and you are not wrong about it IMHO.

    --
    Tatsuhiko Miyagawa
    miyagawa@cpan.org

      How can I tell from another routine in the module (such as INIT) that the subroutine has been imported?

        Sorry for that this is not a direct answer, but you've wrote
        The real reason is that foo requires a bit of initialization, and I don't want to do this unless necessary.
        I think this is completely irrelevant to import/export. Making closure will be enough, and using Autoloader would be another option.

        --
        Tatsuhiko Miyagawa
        miyagawa@cpan.org

Re: How to tell if a sub has been exported?
by perrin (Chancellor) on Oct 05, 2001 at 08:15 UTC
    FYI, mod_perl will only have trouble with that if you use Apache::Registry or Apache::PerlRun, which wrap your code in a sub in order to do their magic. if you write an actual handler module (try it!), this will not be a problem.