in reply to Is there any (performance) benefit to importing functions?

The documentation will (well, should) explain which functions are "exported" by default, and which ones you have to ask for. If not, look in the module's code, and in the @EXPORT array, these are the ones exported by default. The @EXPORT_OK are ones you need to specifically request when loading the module. One can also use %EXPORT_TAGS hash to create tags that can bundle certain groups of functions.

For example, my Bit::Manip distribution exports none of its functions by default, you have to ask for them individually, or you can use the :all tag to load them all in bulk:

use Exporter; our @ISA = qw(Exporter); our @EXPORT_OK = qw( bit_get bit_set bit_clr bit_bin bit_count bit_mask bit_tog bit_toggle bit_on bit_off ); our %EXPORT_TAGS; $EXPORT_TAGS{all} = [@EXPORT_OK];

My WiringPi::API goes one step further, and does use tags to bundle. The distribution is a wrapper of a C library. You can read the export implementation on lines 11-61, but the gist of it is that I provide three tags:

our @EXPORT_OK = (@wpi_c_functions, @wpi_perl_functions); our %EXPORT_TAGS; $EXPORT_TAGS{wiringPi} = [@wpi_c_functions]; $EXPORT_TAGS{perl} = [@wpi_perl_functions]; $EXPORT_TAGS{all} = [@wpi_c_functions, @wpi_perl_functions];

The first tag exports the functions with their original C names (camelCase). The second exports the Perl wrapped names (snake_case). The third, is pretty clear, exports the lot of them. Looking at it now, I don't know why I didn't just set all to @EXPORT_OK, but I digress...). To use them in a use statement, you'd specify them as :wiringPi, :perl or :all.

It's considered bad practice to blindly export all subs by default, as there is high risk that you'll clobber an existing symbol table name. In my App::CopyrightImage module, I have a single public function, which I do export by default:

our @EXPORT = qw(imgcopyright);

The documentation explicitly states we export the one function automatically.

To further, I've even gone beyond using Exporter, and just pee'd all over the user's symbol table to stuff in a function:

sub import { my ($class, %opts) = @_; $self = __PACKAGE__->_new(%opts); my $sub_name = $opts{sub_name} ? $opts{sub_name} : 'plugins'; { no warnings 'redefine'; no strict 'refs'; my $pkg = (caller)[0]; *{"$pkg\::$sub_name"} = \&_plugins; } }

...but that is something rarely done (and shouldn't be done unless there's a very good reason). Of course, that documentation also explicitly and clearly states we do this.

As far as benchmarking, I don't really care. It's startup cost, a one-time thing. To me, benching that would pretty much be far too much optimization without enough benefit. However, if you do bench it, please do post results.

Replies are listed 'Best First'.
Re^2: Is there any (performance) benefit to importing functions?
by choroba (Cardinal) on Feb 10, 2018 at 22:24 UTC
    However, if you do bench it, please do post results.

    #!/usr/bin/perl use warnings; use strict; { package Exported; use Time::HiRes qw{ gettimeofday }; sub foo { gettimeofday } } { package FullName; use Time::HiRes; sub foo { Time::HiRes::gettimeofday } } { package CodeRef; use Time::HiRes; *foo = *Time::HiRes::gettimeofday{CODE}; } use Test::More tests => 2; cmp_ok abs(Exported::foo() - FullName::foo()), '<', 1e-4, 'almost same +'; cmp_ok abs(Exported::foo() - CodeRef::foo()), '<', 1e-4, 'almost same +'; use Benchmark qw{ cmpthese }; cmpthese(-3, { exported => \&Exported::foo, fullname => \&FullName::foo, coderef => \&CodeRef::foo, });

    On my i3 notebook:
    Rate exportedfullnamecoderef
    exported3537621/s -- -6% -72%
    fullname3753422/s 6% -- -70%
    coderef 12498685/s253% 233% --

    Update

    Thanks haukex, the coderef benchmark is wrong. Adding a sub around it slows it to a comparable level in 5.18.2 (blead still shows coderef about 10% faster):
    coderef => sub { CodeRef::foo() },
    ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,

      Thanks choroba!

      So export and fullname are negligibly different, but holy crap coderef! :)

        but holy crap coderef!

        That case isn't really equivalent to the others - the exported and fullname cases have an extra sub { } wrapped around them.

        use warnings; use strict; use Benchmark qw/cmpthese/; sub foo { 1+2==3 } cmpthese(1e8, { one => \&foo, two => sub { foo() }, }); __END__ Rate two one two 24271845/s -- -72% one 86956522/s 258% --