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

Dear Wise Monks,

I recently ran into something strange with the Tk package and I wondered if anyone has an explanation. Somehow, Tk helps another package that is not an Exporter to export its constants.

Here is the example:

This package is trying to export some constants, but it fails to inherit from Exporter, so you would think it could never work.

# Constants.pm package Constants; use constant XX => 0; use constant YY => 1; our @EXPORT = qw(XX YY); 1;
This program will try to use the constants:
# caller.pl use strict; use warnings; use Tk; use Constants; print "sum =",XX + YY,"\n";
Here is the strange thing. With the "use Tk" in place, the program works and prints "sum =3". Without it, the program fails with the expected 'Bareword "XX" not allowed' messages. This is perl version 5.6.1.

Why does Tk have this accidental side-effect? I think it may have something to do with the following line in the Tk.pm header:

use base qw(Exporter DynaLoader);
Does "use base" have side-effects on other packages, causing them to become subclasses of the base list too? This seems quite strange and a potential source of errors. Any ideas?

Replies are listed 'Best First'.
Re: Tk helps another package to export?
by PodMaster (Abbot) on Jan 30, 2003 at 10:19 UTC
    Here's a clue
    E:\new>perl -MConstants -wle"print for keys %Constants::;;print XX+YY" Name "main::XX" used only once: possible typo at -e line 1. import YY EXPORT XX BEGIN print() on unopened filehandle XX at -e line 1. E:\new>perl -MUNIVERSAL -MConstants -wle"print for keys %Constants::;; +print XX+YY" import YY EXPORT EXPORT_FAIL EXPORT_OK XX BEGIN 1
    Smells like a bug to me.

    In my activeperl5.6.1/5.8.0, UNIVERSAL.pm consists of

    require Exporter; *import = \&Exporter::import; @EXPORT_OK = qw(isa can);
    I don't know when that happened/changed, but perl is supposed to load UNIVERSAL AUTOMAGICALLY, so you shouldn't need to say use UNIVERSAL;

    I wanna hear what tye, merlyn and other people in the know have to say.

    update: more clues

    E:\new>perl -MConstants -wle"print for keys %UNIVERSAL::;;print XX+YY" Name "main::XX" used only once: possible typo at -e line 1. import can isa VERSION print() on unopened filehandle XX at -e line 1.
    In Universally unimportant and overused tye says
    (currently, Exporter::import() is called whenever you use a module that doesn't define any import method at all, even it that module doesn't even mention Exporter -- this will probably be "fixed" at some point but with this you can "fix" it now and see if you are using any modules that depend on this "bug").
    I think it's fairly obvious that you should avoid using the package variables @EXPORT unless you also push @ISA, 'Exporter'; cause you'll have unexpected results (and what's the point of an @EXPORT if you don't wanna export anything).


    MJD says you can't just make shit up and expect the computer to know what you mean, retardo!
    ** The Third rule of perl club is a statement of fact: pod is sexy.

      Quoting PodMaster quoting me:

      (currently, Exporter::import() is called whenever you use a module that doesn't define any import method at all, even it that module doesn't even mention Exporter -- this will probably be "fixed" at some point but with this you can "fix" it now and see if you are using any modules that depend on this "bug").

      I was a bit inaccurate there. That is only true if you have already required UNIVERSAL.pm because that file contains:

      require Exporter; *import = \&Exporter::import;
      which is what causes this surprising behavior.

      I really think UNIVERSAL::import needs to be made smarter so that it only calls Exporter::import if called as UNIVERSAL->import( ... ). It is nice that you can do use UNIVERSAL qw( isa can ); but it is not nice to have every package suddenly "inherit" Exporter::import whether it wants to or not just because UNIVERSAL.pm has been required by some other part of the script.

      The only other piece of the mystery is that Tk::Widget does require UNIVERSAL; (and probably isn't the only place where UNIVERSAL.pm gets requested as a result of use Tk, but that is where the debugger found it being loaded).

                      - tye
Re: Tk helps another package to export?
by demerphq (Chancellor) on Jan 30, 2003 at 11:16 UTC
    Im positive that use base has nothing to do with this. However I cannot explain the behaviour. It is odd I agree. I believe it is something wierd in AutoLoader, DynaLoader or Tk's actual code.

    I have tried to reproduce the behaviour using the things that Tk uses, but sofar to no avail. I would report this to Nick Ing-Simmons.

    Updated

    --- demerphq
    my friends call me, usually because I'm late....

Re: Tk helps another package to export?
by batkins (Chaplain) on Jan 30, 2003 at 01:13 UTC
    use base qw(...) is a synonym for @ISA = qw(Exporter...).

    happy perling.

    Update:this information is wrong. please ignore. :)

      Well, actually
      use base qw(Foo Bar);
      is more or less the same as
      BEGIN { require Foo; require Bar; push @ISA, qw(Foo Bar); }
      Which raises an interesting point, prototypes are not respected when a module is required. However they are when they are used.

      --- demerphq
      my friends call me, usually because I'm late....

        prototypes are not respected when a module is required. However they are when they are use

        Wrong. Prototypes are not respected if they are defined too late (i.e. not in the compile time). In this case require is wrapped in BEGIN block so it is the compile time.

        --
        Ilya Martynov, ilya@iponweb.net
        CTO IPonWEB (UK) Ltd
        Quality Perl Programming and Unix Support UK managed @ offshore prices - http://www.iponweb.net
        Personal website - http://martynov.org

      But the "use base" is in package Tk, so the @ISA should have been a @Tk::ISA and not a @Constants::ISA. It still doesn't make sense to me.
Re: Tk helps another package to export?
by tall_man (Parson) on Jan 30, 2003 at 01:07 UTC
    (That should be "sum=1")