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

Hello, I am tired and my brain is having a short circuit. Why does adding the import method break the program? It looks strange to me too, but when I leave the method out, it seems to work...

# Foo package Foo ; require Exporter ; our @ISA = qw( Exporter ) ; our @EXPORT_OK = qw( saySomethingElse ) ; # Add this method and it breaks # sub import { # my $this = shift ; # $this->SUPER::import( @_ ) ; # } sub saySomethingElse { print "Bye World!\n" ; } 1 ;
# main use Foo qw ( saySomethingElse ) ; saySomethingElse() ;
Thanks

Replies are listed 'Best First'.
Re: Exporter. Correct way to override import?
by dave_the_m (Monsignor) on May 04, 2018 at 22:45 UTC
    Replace
    my $this = shift ; $this->SUPER::import( @_ ) ;
    with:
    Foo->export_to_level(1, @_);
    By default, Export::import() adds symbols to its caller's namespace, so it's been adding them to Foo:: rather than main::.

    You have to explicitly tell Exporter to export more than 1 level up.

    See the section in Exporter's docs, 'Exporting Without Using Exporter's import Method'

    Dave.

Re: Exporter. Correct way to override import?
by roboticus (Chancellor) on May 04, 2018 at 22:59 UTC

    Veltro:

    As you know, your program breaks because it interferes with the import function provided by Exporter. This leads to your question of how to properly overload the import function.

    First I'd ask whether you actually need to overload import. If you just want to do some extra work in your module before anyone uses your code, you can do that at the end of your module, like this:

    $ cat Foo.pm package Foo; require Exporter; our @ISA = qw( Exporter ); our @EXPORT_OK = qw( saySomething ); sub saySomething { print "Foo!\n"; } # Special package initialization stuff print "Special FOO.PM initialization complete!\n"; 1; $ cat T.pl #!env perl use lib '.'; use Foo qw( saySomething ); print "Begin\n"; saySomething(); print "End\n"; $ perl t.pl Special FOO.PM initialization complete! Begin Foo! End

    The only time I can think of where you would need to overload import is if (a) import() doesn't do something that you need done, and (b) you're going to create other packages that rely on your package which need that extra behavior. If both of these are the case, I expect you'll need to look at the source code to Exporter and see what the import function does and how to not interfere with it. I've not done so, so I don't have much to offer you in that case. I did, however, look over the Exporter docs, though, and found that there's a section "Exporting Without Using Exporter's import Method" that may give you a starting point.

    ...roboticus

    When your only tool is a hammer, all problems look like your thumb.

      Thanks both Dave and roboticus,

      The thing that I actually tried to solve was slightly different, but I decided to simplify the question because I just knew the problem was how I was using the import function.

      What I was trying to do was:

      # Foo package Foo ; use strict ; use warnings ; require Exporter ; our @ISA = qw( Exporter ) ; our @EXPORT_OK = qw( saySomethingElse ) ; # sub import { # Foo->export_to_level( 1, @_ ) ; # } sub saySomethingElse { print "Good morning!\n" ; } 1 ;
      # Bar package Bar ; use strict ; use warnings ; use base qw( Foo ) ; 1 ;

      In the next code, I wanted both lines to work because I am sometimes using the module Foo and sometimes the module Bar. The 'use Bar...' line refused to work.

      # main use Bar qw ( saySomethingElse ) ; # use Foo qw ( saySomethingElse ) ; saySomethingElse() ;

      Now that I have the import function correct, I got this to work

      Thanks again to both of you! ++

Re: Exporter. Correct way to override import?
by ikegami (Patriarch) on May 06, 2018 at 01:12 UTC

    Exporter uses caller or similar to determine to which package to export. The caller is in package Foo in your example, which is why it's failing. You want

    sub import { ... Exporter->export_to_level(1, @_); ... }
    or
    sub import { ... goto &Exporter::import; }

    Get rid of archaic our @ISA = 'Exporter';. It doesn't make sense, and it hasn't been necessary since 5.8.3 (2004).

      Get rid of archaic our @ISA = 'Exporter';. It doesn't make sense, and it hasn't been necessary since 5.8.3 (2004).

      Correct. But it is still (as of version 5.72) the documented as a valid way to use Exporter. To make things worse, it is still the first example in the Synopsis, and it is in "Good Practices". See also Re^2: Advice on style, 7.5 years ago. There are no relevant changes in the documentation in the last 10 years / 9 versions: http://search.cpan.org/diff?from=Exporter-5.63&to=Exporter-5.72&w=1#lib/Exporter.pm

      Alexander


      Update: Fixed diff link and number of versions (was diff'ing between 5.63 and 5.70)

      --
      Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)

        So what? Even if it is presented as an option, you should still not pick the version that makes no sense (unless you need compatibility with pre-5.8.3 builds of Perl).