This and other RFCs are available on the web at
http://dev.perl.org/rfc/
=head1 TITLE
UNIVERSAL::import()
=head1 VERSION
Maintainer: Michael G Schwern <[EMAIL PROTECTED]>
Date: 18 Sep 2000
Mailing List: [EMAIL PROTECTED]
Number: 257
Version: 1
Status: Developing
=head1 ABSTRACT
UNIVERSAL::import() will be a flyweight method to provide very
simple semantics to export variables and functions.
=head1 DESCRIPTION
Exporter is big and complicated. It is so big it has been split up
into Exporter and Exporter::Heavy. Its so complicated that it takes
264 lines to explain it.
Most of the time, you just want to export some variables and methods.
This part of Exporter is almost trivial to implement that people often
write their own simple import() routines.
UNIVERSAL::import() would take this basic Exporter::import()
functionality and implement it in a very lean fashion. It would
support only three of Exporter::import's features.
@EXPORT - A default list of symbols to export
@EXPORT_OK - A list of symbols to export upon request
@EXPORT_FAIL - A list of symbols which cannot be exported
Tags, "/pattern/", negation, export_to_level(), export_fail() and all
supporting paraphernalia are all left to Exporter. Module version
checking is left to UNIVERSAL::require.
Removal of the more obscure features should make basic exporting
faster and easier to document. So too would it be made much more
efficient if implemented in universal.c.
=head2 UNIVERSAL::import() is only a class method.
Because it is strongly recommended that you not export methods,
import() makes little sense as an object method. If you have an
object for a module, more than likely you're not going to be exporting
functions. C<$obj->import()> should be an explicit run-time error.
This protects against the programming mistake where $class is
accidentally an object. C<$class->import> would silently work, making
the mistake difficult to find. This case should be far more common
than that of desiring to import a module based on an object.
if import() is desired as an object method, it can be easily overridden with:
sub import {
my $proto = shift;
my $class = ref $proto || $proto;
return $class->SUPER::import(@_);
}
Ta da.
=head1 MIGRATION
Replace UNIVERSAL::import() with a method that dies with a q|Can't
locate object method "%s" via package "%s"| so that Class->import()
continues to fail if Class does not implement import() or subclass
Exporter.
Class->can('import') remains a problem. UNIVERSAL::can may have to be
coded with a special case to cause a failure in Perl5 code.
=head1 IMPLEMENTATION
A complete Perl 5 implementation follows:
package UNIVERSAL;
sub import {
my($exporter, @imports) = @_;
my($caller, $file, $line) = caller;
# XXX Can't tell difference between "use Module" and "use Module ()"
unless( @imports ) { # Default import.
@imports = @{$exporter.'::EXPORT'};
}
else {
if( @{$exporter.'::EXPORT_FAIL'} ) {
# This can be cached.
my %fail = map { $_ => 1 } @{$exporter.'::EXPORT_FAIL'};
my($denied) = grep {$fail{$_}} @imports;
_not_exported($denied, $exporter, $file, $line) if $denied;
}
# Because @EXPORT_OK = () would indicate that nothing is
# to be exported, we cannot simply check the length of @EXPORT_OK.
# We must to oddness to see if the variable exists at all as
# well as avoid autovivification.
# XXX idea stolen from base.pm, this might be all unnecessary
my $eokglob;
if( $eokglob = ${$exporter.'::'}{EXPORT_OK} and *$eokglob{ARRAY} ) {
if( @{$exporter.'::EXPORT_OK'} ) {
# This can also be cached.
my %ok = map { $_ => 1} @{$exporter.'::EXPORT_OK'};
my($denied) = grep {!$ok{$_}} @imports;
_not_exported($denied, $exporter, $file, $line) if $denied;
}
else { # We don't export anything.
_not_exported($imports[0], $exporter, $file, $line);
}
}
}
_export($caller, $exporter, @imports);
}
sub _export {
my($caller, $exporter, @imports) = @_;
# Stole this from Exporter::Heavy. I'm sure it can be written better
# but I'm lazy at the moment.
foreach $sym (@imports) {
# shortcut for the common case of no type character
(*{"${caller}::$sym"} = \&{"${exporter}::$sym"}, next)
unless $sym =~ s/^(\W)//;
my $type = $1;
*{"${caller}::$sym"} =
$type eq '&' ? \&{"${exporter}::$sym"} :
$type eq '$' ? \${"${exporter}::$sym"} :
$type eq '@' ? \@{"${exporter}::$sym"} :
$type eq '%' ? \%{"${exporter}::$sym"} :
$type eq '*' ? *{"${exporter}::$sym"} :
do { require Carp; Carp::croak("Can't export symbol: $type$sym") };
}
}
sub _not_exported {
my($thing, $exporter, $file, $line) = @_;
die sprintf qq|"%s" is not exported by the %s module at %s line %d\n|,
$thing, $exporter, $file, $line;
}
1;
Of course, the efficiency of the implementation can be tightened up.
Its just a prototype.
=head1 REFERENCES
RFC 233 - Replace Exporter with a better scaling mechanism.
RFC 253 - UNIVERSAL::require()
L<Exporter>