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