[% setvar title UNIVERSAL::require() %]

This file is part of the Perl 6 Archive

Note: these documents may be out of date. Do not use as reference!

To see what is currently happening visit http://www.perl6.org/

TITLE

UNIVERSAL::require()

VERSION

  Maintainer: Michael G Schwern <schwern@pobox.com>
  Date: 17 Sep 2000
  Mailing List: perl6-language@perl.org
  Number: 253
  Version: 1
  Status: Developing

ABSTRACT

UNIVERSAL::require() allows modules to be loaded from variables with $module->require rather than the current eval "require $module";

DESCRIPTION

Currently, to load a module one uses either require() or use() with a bareword expression. require $variable is reserved for loading and evaling files. It is not obvious how one loads a module from the value of a variable. Currently, its done like this:

    $module = "Some::Module";
    eval "require $module";

This has two problems. First, its unintuitive. Secondly, $@ is often accidentally not checked, so if the module load fails the error will not be noticed.

As a solution, a UNIVERSAL:::require() method can be added with the following syntax:

    $module = "Some::Module";
    $module->require;

This is neatly analagous with $module->import and causes a run-time error should the module fail to load.

What about use()?

UNIVERSAL::use() and thus $module-use> would be an obvious analogy, but unfortunately use() is a compile-time beastie. Variables and methods are run-time. It would be confusing for use() to be compile-time and UNIVERSAL::use() to be run-time, so UNIVERSAL::use() should not be.

Instead, this code suffices:

    BEGIN {
        $module->require;
        $module->import;
    }

We see here how neatly the UNIVERSAL::require() syntax lines up with Exporter::import().

Of course, if you really want a run-time use() method you can easily write one.

Version checking

The lack of a UNIVERSAL::use() leaves out module version checking (ie. use Some::Module 0.23). UNIVERSAL::require() can take on this feature by taking a version as an argument.

    $module->require(0.23);

UNIVERSAL::require() is only a class method.

What should happen if UNIVERSAL::require() is called as an object method? Should it eval "require ".ref $obj or should it be an error? Because the situation is very rare when you will have an object from a class which has not yet been required, UNIVERSAL::require() should only work as a class method. $obj-require> should be an explicit run-time error.

If require() is desired as an object method, it can easily be overridden with:

    sub require {
        my $proto = shift;
        my $class = ref $proto || $proto;
        return $class->SUPER::require;
    }

Ta da.

IMPLEMENTATION

A complete Perl 5 implementation follows:

    package UNIVERSAL;   

    sub require {     
        my($class, $want_version) = @_;
     
        die("UNIVERSAL::require() can only be run as a class method")  
          if ref $class; 
     
        die("UNIVERSAL::require() takes no or one arguments") if @_ > 2; 
        
        # Load the module.
        my $return = eval "CORE::require $class";
        
        # Check for module load failure.
        if( $@ ) {
            $@ =~ s/ at .*?\n$//;
            die sprintf "$@ at %s line %d.\n", (caller)[1,2];
        }
        
        # Module version check.
        my $have_version = ${$class.'::VERSION'};
        if( @_ == 2 and $have_version < $want_version ) {
            die sprintf "%s version %s required--this is only version %s ".
                        "at %s line %d\n", $class, $want_version, 
                                           $have_version, (caller)[1,2];
        }

        return $return;   
    } 

this could be added to UNIVERSAL.pm and eventually implemented in universal.c. It could even be safely added to Perl 5.

REFERENCES

RFC 103 laments that require $class does not DWIM.