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

Having switched to Sub::Exporter from Exporter, I came across functionality differences. If one of your sub routine names is not defined, Sub::Exporter croaks where as Exporter does not export that name.

Currently I have a number of constants that get AUTOLOADed through:

# This AUTOLOAD is used to 'autoload' constants from the constant() XS + function. sub AUTOLOAD { my $constname; our $AUTOLOAD; ($constname = $AUTOLOAD) =~ s/.*:://; croak "&Blah::constant not defined" if $constname eq 'constant'; my ($error, $val) = constant($constname); if ($error) { croak $error; } { no strict 'refs'; *$AUTOLOAD = sub { $val }; } goto &$AUTOLOAD; }

(this being the standard h2xs boilerplate code).

Is it better practice to setup 1 sub routine for each constant such as:

foreach my $constname (@constants) { { no strict 'refs'; *$constname = sub { use strict; my ($error, $val) = constant($constname); if ($error) { croak $error; } return $val; } } }

for Sub::Exporter?

The only downside I can see is the added code overhead, but not having AUTOLOAD around seems like a win.

Replies are listed 'Best First'.
Re: Using sub routines or AUTOLOAD for XS constants
by chromatic (Archbishop) on Jan 01, 2010 at 20:23 UTC

    If you're getting the error message "can't locate exported subroutine $name via $class" from Sub::Exporter's default_generator(), the best option is to override can() in your package when you use AUTOLOAD(). That's a good practice anyway, though.

    I haven't tested this code, but something like this should work:

    sub can { my ($class, $name) = @_; return if $name eq 'constant'; my ($error, $val) = constant($name); return if $error; my $sub = sub () { $val }; { no strict 'refs'; *{ $class . '::' . $name } = $sub; } return $sub; }
      Sub::Exporter uses can? That's a bug. can is for methods, and it makes no sense to export methods.
        can is for methods...

        I agree in principle, but what's the difference in practice between a method and a function, at least when you're groveling through a package's symbol table?

        There's likely a bug lurking in Sub::Exporter here as well, if it ever tries to export an inherited function.

      Yes that is exactly what I was looking for. Although I had to add

      return \&{$class . '::' . $name} if (defined(&{$name}));

      for having the non-constant subs reachable.

      Thanks for the nudge in the right direction.