Michael G Schwern: # I've rearranged the proposed features a bit to put the long objections # at the bottom. # # Brent Dax wrote: # > I've been thinking about improvements that could be made to # Exporter for # > Perl 6. # > 3. Warnings about conflicts: # > use warnings 'Exporter'; # > sub Dumper { ... } # > use Data::Dumper qw(Dumper); # > #prints out a warning (not just 'redefined subroutine', either). # # This would be nice. In fact, it could be retrofitted onto perl5's # Exporter. # # > 4. For modules, saying 'use Exporter' should be enough to # get import. # > If you don't want Exporter's import(), just C<use Exporter()>. # # Very nice. Exporter::Lite does just that. # # > 5. In addition to @EXPORT/@EXPORT_OK/%EXPORT_TAGS, provide # a way to do # > it on the 'use Exporter' line. # # Getting rid of the @EXPORT* variables entirely would simplify both the # interface and the internals. Exporter could then do a lot more # caching and pre-calculating than it does now since it doesn't have to # worry "Did they alter @EXPORT since the last time import() was # called?"
That may be a good idea. I'll consider it. Can anybody think of a reason against it? # However, shoving everything onto the use line seems of somewhat # dubious use. For starters, how do you say "don't export import()" and # "export these variables please" at the same time? You start getting # into special "dont_export" flags. Huh? # Why not just a regular function or method? I like the idea of just dealing with Exporter in one statement and then forgetting it even exists. To me, something like: use Exporter; our $Exp=new Exporter; $Exp.default=qw(foo bar); $Exp.ok=qw(baz quux); $Exp.tags=(':B' => [qw(bar baz)]); is little better than: use Exporter; our @ISA='Exporter'; our @EXPORT=qw(foo bar); our @EXPORT_OK=qw(baz quux); our %EXPORT_TAGS=(':B' => [qw(bar baz)]); A little less typing, perhaps, but still too much for my tastes. # > 1. Choosing where to export to: # > use Data::Dumper 'Dumper' => 'dumpvar'; # > #exports Data::Dumper::Dumper to Main::dumpvar (or whatever) # > # > 2. Built-in switch handling: # > use Data::Dumper ('Dumper' : qw(+Indent=2 +Useqq)); # > #imports Dumper, sets $Data::Dumper::Indent=2, and # > # does $Data::Dumper::Useqq is true # # The above are both rare and of dubious practice. But that's not the I disagree. The first one is something I thought of because of the p5p 'exporting considered harmful' thread (i.e. importing 'Dumper' to something more sensible); the second one is something many modules implement hacks to do. (Carp and CGI both do it in some way; Data::Dumper, Test::(More|Simple) and most other modules with configuration variables could benefit from it.) # real problem I have with it. # # What's the biggest problems with Exporter? # # 1) The man page is Big and Confusing to the first time module author. # 2) Exporter is difficult to extend. # 3) The internals are twisty and confusing. # # And they all stem from one issue: # # 4) Exporter tries to do too much already. I can see abstracting out the options into Exporter::Options (or something), but I don't think the pairwise thing can do so. I do think that we should get rid of '!symbol' and especially '/regex/'; they seem like an unnecessary complication. # The two biggest blocks to getting your first modules is figuring out # Makefile.PL (and thus MakeMaker) and figuring out how to export # functions. Both are confusing because the man pages are more # reference than tutorial. They have to be references because the # interfaces are big. The interfaces are big because they try to # implement lots of features. They try to implement every feature # because they're difficult to extend (ie. if you want to add to # Exporter you have to rewrite Exporter). They're difficult to extend # because it wasn't written to be extensible, there's lots of features, # and in Exporter's case, it does backflips to try and be lightweight if # you're only using a subset of its functionality (the Exporter::Heavy # hack). Maybe it's just me, but I didn't find Exporter difficult to use. At the basic levels most people use it at, it's just: -Stuff the default exports into @EXPORT. -Stuff anything else that's public into @EXPORT_OK. Tags aren't much more difficult either. @EXPORT_FAIL is just weird, though--I don't know why it's there. # Its interesting to look at who is using what bits of Exporter. Here's # a very rough breakdown (crude scanner attached, all praise forwarded # to Jeff Friedl). # # 1271 .pm files scanned # 279 using or requiring Exporter # 178 using anything beyond @EXPORT and @EXPORT_OK # 125 anything beyond @EXPORT, @EXPORT_OK and %EXPORT_TAGS # 83 using %EXPORT_TAGS # 113 having their own import() # 4 using @EXPORT_FAIL # # which shows a few interesting things: # # 1) Exporter isn't being used as much as I'd thought. Lots of OO and 'heavy' or 'backend' modules, I suspect. # 2) More people use %EXPORT_TAGS than I'd thought. # 3) A lot more people are finding it necessary to write their own # import() routine than I thought. # 4) Almost nobody is using @EXPORT_FAIL (its just Carp and Exporter). And Carp is only using it to detect a "verbose" switch. # So here's the priority list I'd write out for Exporter::NG: # # 1) Support functionality equivalent to @EXPORT, @EXPORT_OK and # %EXPORT_TAGS and that's it. # 2) Make the man page start with a quick tutorial. # 3) Make it extensible. How would you do this? My idea is that when you load Exporter::Whatever, it passes a couple coderefs to Exporter::register (or something). Those coderefs are given first whack at the parameter list. In other words: module Exporter::Options; use Exporter(); Exporter::register(&onimport, &onunimport); sub onimport(@args is rw) { for(@args) { next unless defined; next unless s/-//; #stringifies pairs if(/=/) { my($left, $right)=split '='; ${%Exporter::From::{$left}=$right; undef $_; } else { ${%Exporter::From::{$_}} is true; undef $_; } } } sub onunimport(@args is rw) { for(@args) { next unless defined; next unless s/-//; ($_)=split /=/; undef ${%Exporter::From::{$_}}; undef $_; } } # The important thing being that Perl 6's exporter has a small, simple, # easy to explain interface. That it *doesn't* try to shove every # feature into one namespace. And that its easy for people to write # their own exporters. # # Then I'd look at those 113 modules that found it necessary to override # Exporter's functionality (I've attached a list) and see what they're # doing. Once you've got a handle on that, move to step four: I've removed the things from your list where the reason was blindingly obvious (pragma, source filter, interface is based on 'use'...) and reattached it; that brings it down to 68. Oddly enough, B::* and O.pm didn't appear on your list. Your own Test::Simple and Test::More modules were on the list; unless I'm mistaken, that's because of 'use Test::More tests => N', which could be handled by options. ;^) # 4) Write seperate extensions based on the above. Just remember that some things are simply too weird. For example, I don't think we should try to accommodate Inline as an Exporter extension. :^) --Brent Dax [EMAIL PROTECTED] Configure pumpking for Perl 6 "Nothing important happened today." --George III of England's diary entry for 4-Jul-1776
Attribute/Types.pm Parse/RecDescent.pm AnyData/Format/HTMLtable.pm AnyData/Format/XML.pm AnyLoader.pm CGI/Debug.pm CPAN/Site.pm Carp/Assert.pm Class/Contract.pm Class/Contract/Production.pm Class/MethodMaker.pm Class/Prototyped.pm Convert/Units/Base.pm Devel/SearchINC.pm ExtUtils/AutoInstall.pm Getargs/Long.pm Hook/LexWrap.pm IO/LockedFile.pm ImportTest.pm Mail/Audit.pm Mail/Field.pm Mail/Mailer.pm Math/BigFloat.pm Math/BigInt.pm Memoize/NDBM_File.pm Memoize/SDBM_File.pm Net/LDAP.pm Net/LDAP/ASN.pm Net/LDAP/Extra.pm POE.pm POE/Kernel.pm POE/NFA.pm POE/Preprocessor.pm POE/Session.pm Pod/Coverage.pm Pollute.pm Pollute/Persistent.pm RTF/Group.pm Test/Builder.pm Test/More.pm #no options (?) Test/Simple.pm #no options (?) YAPE/Regex.pm uny2k.pm private.pm protected.pm public.pm CGI.pm #speed hack (?) CGI/Carp.pm Class/Struct.pm Env.pm Fatal.pm File/stat.pm FileHandle.pm Getopt/Long.pm Math/BigInt.pm Net/hostent.pm Net/netent.pm Net/protoent.pm Net/servent.pm User/grent.pm User/pwent.pm Debconf/Client/ConfModule.pm Debian/DebConf/Client/ConfModule.pm Debhelper/Dh_Getopt.pm LWP/Debug.pm LWP/Simple.pm Mail/Field.pm Mail/Mailer.pm