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

I'm developing a package that can be used with tied variables, but can't seem to make autoloading work on the tie routines (TIEWHATSIT, FETCH, STORE...).

As long as I keep these routines ahead of the __END__ statement my tests work well, but when I put them after, perl complains that it can't find them. My package contains the following AUTOLOAD routine:
our $AUTOLOAD; sub AUTOLOAD { # this is used to 'autoload' constants from the constant() # XS function. If a constant is not found then control is passed # to the AUTOLOAD in AutoLoader. my $constname; ($constname = $AUTOLOAD) =~ s/.*:://; croak "& not defined" if $constname eq 'constant'; my $val = constant($constname, @_ ? $_[0] : 0); if ($! != 0) { if ($! =~ /Invalid/ || $!{EINVAL}) { $AutoLoader::AUTOLOAD = $AUTOLOAD; goto &AutoLoader::AUTOLOAD; } else { croak "Your vendor has not defined MMA macro $constname"; } } eval "sub $AUTOLOAD { $val }"; goto &$AUTOLOAD; }
Also things seem to work the same whether there's a require AutoLoader or use AutoLoader near the start of my package.

The routine above is slightly different than the one shown on the perl.org Autoloader page. When I tried to edit mine to be exactly like the one on the perl.org page, big trouble broke loose, with complaints about constants not being allowed to be used under strict (and such). Of course I may have edited the routine imperfectly.

My Makefile.PL file uses ExtUtils::MakeMaker, and the right things seem to happen during make, like splitting into the right .al files.

Is there anything incompatible between tie subroutines and autoloading? If not, how should I proceed toward making autoloading work?

cmac
www.animalhead.com

Replies are listed 'Best First'.
Re: autoloading tie routines
by ysth (Canon) on Feb 02, 2009 at 07:54 UTC
    No, there should be no incompatibility; put in some debugging print statements and see if it's getting to the goto, or if not, why not. Are you use'ing Errno, etc.?

    Here's a complete working example:

    package Foo; use strict; use warnings; use Errno "EINVAL"; use Tie::Scalar; use AutoLoader; use Carp; sub constant { $!=EINVAL() } our $AUTOLOAD; sub AUTOLOAD { # this is used to 'autoload' constants from the constant() # XS function. If a constant is not found then control is passed # to the AUTOLOAD in AutoLoader. my $constname; ($constname = $AUTOLOAD) =~ s/.*:://; croak "& not defined" if $constname eq 'constant'; my $val = constant($constname, @_ ? $_[0] : 0); if ($! != 0) { if ($! =~ /Invalid/ || $!{EINVAL}) { $AutoLoader::AUTOLOAD = $AUTOLOAD; goto &AutoLoader::AUTOLOAD; } else { croak "Your vendor has not defined MMA macro $constname"; } } eval "sub $AUTOLOAD { $val }"; goto &$AUTOLOAD; } 1; __END__ sub TIESCALAR { goto &Tie::StdScalar::TIESCALAR } sub FETCH { goto &Tie::StdScalar::FETCH } sub STORE { goto &Tie::StdScalar::STORE }
    $ perl -wle'use Foo; tie $x, "Foo"; $x="42"; print $x; print for grep +/auto/, values %INC' 42 auto/Foo/autosplit.ix ./auto/Foo/STORE.al ./auto/Foo/TIESCALAR.al ./auto/Foo/FETCH.al
      I put in a
      use Errno qw(EINVAL); use Tie::Scalar;
      as you had, and a couple of print statements in my AUTOLOAD:
      sub AUTOLOAD { my $constname; ($constname = $AUTOLOAD) =~ s/.*:://; croak "& not defined" if $constname eq 'constant'; my $val = constant($constname, @_ ? $_[0] : 0); if ($! != 0) { if ($! =~ /Invalid/ || $!{EINVAL}) { print "just before AUTOLOAD\n"; $AutoLoader::AUTOLOAD = $AUTOLOAD; goto &AutoLoader::AUTOLOAD; } else { croak "Your vendor has not defined MMA macro $constname"; } } print "just before eval\n"; eval "sub $AUTOLOAD { $val }"; goto &$AUTOLOAD; }
      No sign of output from the print statements. Here is the output, both under test harness and standalone:
      $ make test PERL_DL_NONLAZY=1 /usr/bin/perl "-MExtUtils::Command::MM" "-e" "test_h +arness(0, 'blib/lib', 'blib/arch')" t/*.t t/6_tiedScalars....1/18 Undefined subroutine &IPC::MMA::Scalar::TIESCA +LAR called at t/6_tiedScalars.t line 42. # Looks like you planned 18 tests but ran 4. # Looks like your test exited with 255 just after 4. t/6_tiedScalars.... Dubious, test returned 255 (wstat 65280, 0xff00) Failed 14/18 subtests Test Summary Report ------------------- t/6_tiedScalars (Wstat: 65280 Tests: 4 Failed: 0) Non-zero exit status: 255 Parse errors: Bad plan. You planned 18 tests but ran 4. Files=1, Tests=4, 0 wallclock secs ( 0.03 usr 0.00 sys + 0.05 cusr + 0.00 csys = 0.09 CPU) Result: FAIL Failed 1/1 test programs. 0/4 subtests failed. *** Error code 255 Stop in /build/IPC-MMA-0.5. $ t/6_tiedScalars.t 1..18 ok 1 - created shared mem ok 2 - read available mem ok 3 - make scalar ok 4 - effect on available mem is -16 Undefined subroutine &IPC::MMA::Scalar::TIESCALAR called at t/6_tiedSc +alars.t line 42. # Looks like you planned 18 tests but ran 4. # Looks like your test exited with 255 just after 4. $
      To complete the picture, here's line 42 of the .t file:
      ok (tie(my $tiedScalar, 'IPC::MMA::Scalar', $scalar), "tie scalar");
      Can you (anyone) think of some other requirement I've overlooked, or where else things might have gone wrong?
        It occurs that I have a problem with naming structure inherited from the guy who wrote the package that I'm working to supercede. He (I) have a module/package named IPC::MM (IPC::MMA).

        Using this, people want to tie to names IPC::MM::Scalar and IPC::MM::Hash (IPC::MMA::Scalar, IPC::MMA::Array, IPC::MMA::Hash). The way he did this was to write out the names of the tie routines in full in MM.pm, like this:
        # Preloaded methods go here. sub IPC::MM::Scalar::TIESCALAR { my $class = shift; my ($val) = @_; return bless \$val, $class; }
        This works in preloaded form, but it seems it can't be autoloaded.

        In my .xs file there is a nice little header:
        MODULE = IPC::MMA PACKAGE = IPC::MMA
        and one can have other headers that vary these names. But I don't know of any comparable structure on the .pm side. Assuming that I want to keep the inherited naming structure, what can I do in the .pm file (files?) to straighten out this mess?

        cmac
        www.animalhead.com