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

I have been wondering why I should use Exporter for some time now. I have read the man-pages, and it tells me that it has a neat import method that is good for me. I haven't quite figured why it is good for me yet, so I hereby seek the enlightenment of the esteemed Monastery.

I usually write OO modules, and as far as I have understood, using Exporter on object-oriented modules isn't really necessary, as 'all' methods should be connected to an object. I can see uses for Exporter in OO when making abstract factories, for example, but where else would Exporter be useful?

I started thinking about this while implementing a module with two examples from Jeffrey Friedl's Owl. I enclose the module below, to anchor my question in something real. To contrast the last paragraph, this module is procedural, and it uses Exporter to 'publish' its two methods into the namespace where it is used.

As an aside, I am aware of the performance penalty imposed by using $&. I have left them in, as this is primarily an excercise.

package RegexDebugger; require EXPORTER; @ISA = qw(Exporter); @EXPORT_OK = qw(traceMatch findLongestMatch); use strict; sub traceMatch { my ($string, $regex ) = @_; my $matchtrace = qr{ (?{print "Match at [$`<$&>$']\n"}) (?!) }x; $string =~ m{$regex$matchtrace}; } sub findLongestMatch { my ($string, $regex) = @_; my $longest = undef; my $recordpossiblematch = qr{ (?{ # Checks if this is the longest match if( not defined( $longest ) or length( $& ) > length( longest +) ){ $longest = $&; } }) (?!) # Force failure to find next 'match' }x; $string =~ m{$regex$recordpossiblematch}; return $longest; } 1; =head1 NAME RegexDebugger - Utility functions for debugging regular expressions =head1 SYNOPSIS Implementes two uses of embedded code in regular expressions as descri +bed in the Owl Book. Provides two functions, one that finds the longest ma +tch and another that prints all possible matches. $longest = &RegexDebugger::findLongestMatch( "oneselfsufficient", qr{one(self)?(sufficient)?} ); &RegexDebugger::traceMatch( "123", qr{\d+} ); =head1 DESCRIPTION Jeffrey Friedl's excellent "Mastering Regular Expressions" gives some +neat examples of embebbed code constructs in perl regular expressions. As t +hese examples were both useful and enlightening, I implemented them as an excercise. Putting them into a separate module seemed like the next lo +gical step after abstracting the functionality of the examples into function +s. =over =item findLongestMatch( STRING, EXPRESSION ) Applies the regular expression object given by B<EXPRESSION> to B<STRI +NG> and returns the longest match. The example given in the Owl: my $longest = &RegexDebugger::findLongestMatch( "oneselfsufficient +", qr{one(self)?(sufficient)?} ); print "Longest match found '$longest'.\n" if $longest; Results in: Longest match found 'oneselfsufficient'. =item traceMatch( STRING, EXPRESSION ) Applies the regular expression object given by B<EXPRESSION> to B<STRI +NG> and prints out all possible matches. This will force a lot of backtrac +king, so complicated regexes on large strings may provoke a tea break. Again, we let the Owl do the talking: &RegexDebugger::traceMatch( "123", qr{\d+} ); Gives: Match at [<123>] Match at [<12>3] Match at [<1>23] Match at [1<23>] Match at [1<2>3] Match at [12<3>] =back =head1 AUTHOR Per Christian Nødtvedt =head1 CREDITS Maximum respect and gratitude to the author of the Owl, Jeffrey Friedl +, who wrote the regular expressions used in this module. May his days be lon +g and his nights productive.
pernod
--
Mischief. Mayhem. Soap.

Replies are listed 'Best First'.
Re: Why should I use Exporter?
by ctilmes (Vicar) on Jun 13, 2003 at 10:52 UTC
    You seem to grasp this already.

    I usually write OO modules, and as far as I have understood, using Exporter on object-oriented modules isn't really necessary, as 'all' methods should be connected to an object.

    Right.

    ... this module is procedural, and it uses Exporter to 'publish' its two methods into the namespace where it is used.

    Right.

    It is useful for making it easy for procedural modules to publish symbols into the namespace where they are used.

    Also consider Exporter::Lite, Exporter::Simple and other Exporter::*.

Re: Why should I use Exporter?
by hardburn (Abbot) on Jun 13, 2003 at 13:49 UTC

    You're right--for OO modules, you usually wouldn't use Exporter. There are plenty of perfectly good modules out there that never touch the thing. Though even in an OO module, you might want to use it because:

    • Creating a secondary functional interface (like what CGI.pm does)
    • Allowing certain constants to be accessible outside your module
    • Other reasons (???)

    ----
    I wanted to explore how Perl's closures can be manipulated, and ended up creating an object system by accident.
    -- Schemer

    Note: All code is untested, unless otherwise stated

      Creating a secondary functional interface (like what CGI.pm does)
      I don't like this at all. If you want to provide a secondary functional interface, please add a Foo::Bar::Functions or Foo::Bar::Simple module or some such instead. That way, the baggage doesn't have to be dragged around by everyone who probably doesn't even need it, nor adds extra mess in the main module to maintain. It also, and this I consider the greatest benefit, signficantly reduces the temptation to do dangerous and crufty things like trying to have one and the same subroutine handle both OO and non-OO calling conventions.

      Makeshifts last the longest.

Re: Why should I use Exporter?
by tall_man (Parson) on Jun 13, 2003 at 15:30 UTC
    Here's a real-life case where Exporter was useful to me:
    BEGIN { if ($^O =~ /Win/) { eval "use Tricky_Win;" } else { eval "use Tricky_Linux;" } }
    I made two portability modules, each exporting the same function names. Then the rest of the code can use the exported functions without worrying about where they came from.
      Since Perl 5.8, the if module is in the core. With it you can write this like
      use if $^O =~ /Win/, q(Tricky_Win); use if $^O !~ /Win/, q(Tricky_Linux);

      Makeshifts last the longest.

Re: Why should I use Exporter?
by chunlou (Curate) on Jun 13, 2003 at 20:44 UTC
    Though not a recommended practice (in theory), one could put both OO and non-OO codes in a package. In that case, you would use Exporter for the non-OO code. Take the following as an example

    There are a _DB.pm...
    # Constructor # Usage: $MyDB = DB::MyDB->dbconnect("db", "username", "pwd") sub dbconnect { # stuff } # Usage: $tbl = $MyDB->selectall_tbl($select_statement) # where $tbl is a 2D array sub selectall_tbl { # stuff } 1 ;
    .. and a MyDB.pm...
    package DB::MyDB ; require Exporter ; @ISA = qw(Exporter) ; @EXPORT = qw(print_tbl) ; use DBI ; use strict ; use DB::_DB ; # OO stuff # Usage: print_tbl($tbl) # where $tbl = $MyDB->selectall_tbl($select_statement) # return nice text result sub print_tbl { # stuff } 1 ;
    ... and a MyWebDB.pm
    package DB::MyWebDB ; use Apache::Reload ; use strict ; use DB::_DB ; # OO stuff 1 ;
    _DB.pm contains all the OO stuff for DB access--which basically forms a base object. But there are an Apache environment and a regular environment, where you might need additional methods/subroutines specific for them respectively. Well, you could write some child objects, which inherit the base object from _DB.pm, with additional methods.

    Or, more lazily, you could just write some subroutines and export them. Since subroutines (or closure, for that matter) are theoretically less CPU- and memory-expensive than objects and methods, and in Perl, less code to write, it might not be all that unreasonable a thing to do in Perl--which, as a good thing, doesn't force you to program one way or the other. Just as in Java when you need to write an utility class, which contains no data and nothing but class methods, in Perl you just write a "package."

    In other words, the question one might ask is: are these really methods, or could these just be subroutines or closure?

    (O, yah, you could merge MyDB.pm and MyWebDB.pm together by dynamically determining where you are, as suggested in a previous reply, in case you want to get cute.)