Does the first example with the typeglobs have disadvantages compared to the second example?
package Some::Module::Win32;
use strict;
use 5.10.0;
use Exporter 'import';
our @EXPORT_OK = qw(public);
use Some::Module;
*_func_one = \&Some::Module::_func_one;
*_func_two = \&Some::Module::_func_two;
*_func_three = \&Some::Module::_func_three;
sub public {
my $s = _func_one();
for my $i ( 0 .. $s ) {
say _func_two( $i );
}
say _func_three( $s );
}
1;
package Some::Module::Win32;
use strict;
use 5.10.0;
use Exporter 'import';
our @EXPORT_OK = qw(public);
use Some::Module;
sub public {
my $s = Some::Module::_func_one();
for my $i ( 0 .. $s ) {
say Some::Module::_func_two( $i );
}
say Some::Module::_func_three( $s );
}
1;
Your first example kind of shows how
Exporter
works: by assigning typeglobs. But there is an important difference: when the functions are imported. This is mostly important when a subroutine has a prototype. Prototypes need to be known during parsing, and therefore have to be known in theBEGIN
phase.use
– which usually callsimport
on the used package – is processed in theBEGIN
phase.You should also realize that in your first example, users of your code can now
Some::Module::Win32::_func_one()
whereas this isn't possible in the 2nd example (unlessSome::Module
exports_func_one
.Here is a version that imports the function in the correct phase:
And if you want to, you can use a module like
namespace::autoclean
to remove any foreign imports from the symbol table once they are no longer needed by you.Another strategy would be to put the coderefs into lexical variables. However, the syntax is a bit ugly, and any prototypes are completely ignored:
This does not touch the symbol table, and could therefore be considered a very “clean” solution.
Your second version may be more verbose, but it has the advantage of being very explicit, which may make the code easier to understand for a reader or maintainer. It is the solution I often end up using.
Marpa::R2::Inner::Scanless::G::SYMBOL_IDS_BY_EVENT_NAME_AND_TYPE
)