"Undefined subroutine" error (but it's defined, I think?)

Ask a Question related to PERL Miscellaneous, Design and Development.

  1. #1

    Default "Undefined subroutine" error (but it's defined, I think?)

    I have a program divided into 3 modules plus a main script, and some of
    the modules call functions within other modules. Most of the time this
    works fine, but occasionally I get an error like this:
    > Undefined subroutine &My::Misc::DB_Disconnect called at My/Misc.pm line 18.
    even though I made sure the caller (here Misc.pm) had imported all the
    functions of the other module. Hence, I don't understand the reason
    behind this error. I can get it to work fine by just replacing the
    DB_Disconnect() call in Misc.pm with &My::Misc::DB_Disconnect(), but
    that seems like a kludge, and I'd like to get a better understanding of
    what's going on. :-)

    Here's what happens when I run the program (under perl 5.6.1):
    > $ ./test.pl
    > Error: /dev/null is full!
    > Disconnecting from DB...
    > Undefined subroutine &My::Misc::DB_Disconnect called at My/Misc.pm line 18.
    I isolated the problem to the "use My::SOAP;" line in DB.pm, but I need
    it there because some of the DB functions operate on SOAP data. So I
    left it there and poked around some more...

    I then isolated the real problem to be the "use My::Misc;" line in
    SOAP.pm, but again I need that line there, because the SOAP subs call
    a general untainting function in Misc.pm before returning the data.

    Here's the four files in question (I deleted everything but the bare
    minimum to reproduce this behavior):


    ----- ~/test.pl ---------------------------------
    #!/usr/bin/perl -w

    use strict;
    use My::DB;
    use My::Misc;

    my $dbh = DB_Connect();
    SafeError($dbh, '/dev/null is full!');


    ----- ~/My/DB.pm --------------------------------
    # Database functions
    package My::DB;

    use strict;
    use Exporter;
    use My::SOAP; # XXX this line causes the problem
    use vars qw(@ISA @EXPORT);
    @ISA = ('Exporter');
    @EXPORT = qw(DB_Connect DB_Disconnect);

    sub DB_Connect {
    # stub function, always returns true
    my $dbh = 1;
    return ($dbh);
    }

    sub DB_Disconnect {
    # stub function, always returns true
    my ($dbh) = @_;
    return (1);
    }

    1;


    ----- ~/My/Misc.pm ------------------------------
    # Miscellaneous functions (error handling, logging, untainting, etc.)
    package My::Misc;

    use strict;
    use Exporter;
    use My::DB;
    use vars qw(@ISA @EXPORT);
    @ISA = ('Exporter');
    @EXPORT = qw(SafeError);

    sub SafeError {
    my ($dbh, $msg) = @_;

    print "Error: $msg\n";

    if ($dbh) {
    print "Disconnecting from DB...\n";
    DB_Disconnect($dbh);
    }

    exit 1;
    }

    1;


    ----- ~/My/SOAP.pm ------------------------------
    # SOAP functions, for exchanging data with remote site
    package My::SOAP;

    use strict;
    use Exporter;
    use My::Misc; # XXX this line causes the problem
    use vars qw(@ISA @EXPORT);
    @ISA = ('Exporter');
    @EXPORT = qw(GetRemoteData);

    sub GetRemoteData {
    # stub function, always returns true
    return (1);
    }

    1;

    valerian2@hotpop.com Guest

  2. Similar Questions and Discussions

    1. Stuck email, getting error "undefined mailbox domainstring is null"
      Recently there have been numerous emails in our system that are being moved to the undelivered folder. The following is the error that displays in...
    2. IE only "Element ... undefined in SESSION" error whencalled by Alia/Canonical Name
      I repeatedly get the error "Element .. undefined in SESSION", when using IE to browse to a site using a alias/cname for the site. I've got an...
    3. Error "Element LOCALE is undefined in REQUEST"
      Hi, Can someone help on this error: Element LOCALE is undefined in REQUEST. Thanks in advance Pandu
    4. (Drupal function) getting error : "notice : Undefined index ?"
      hi, i have installed drupal 4.2.0 without any problems. but when i try to connect to my local webserver i get errors: "notice : Undefined...
    5. Error in CreatObject(""): 32797: Application-defined or object-define error
      Hi, I am getting "Application-defined or object-define error" when trying to instantiate an MTS component. However, when I run the VB source-code...
  3. #2

    Default Re: "Undefined subroutine" error (but it's defined, I think?)

    [email]valerian2@hotpop.com[/email] wrote:
    > I have a program divided into 3 modules plus a main script, and some of
    > the modules call functions within other modules. Most of the time this
    > works fine, but occasionally I get an error like this:
    >
    >>Undefined subroutine &My::Misc::DB_Disconnect called at My/Misc.pm line 18.
    >>
    > even though I made sure the caller (here Misc.pm) had imported all the
    > functions of the other module. Hence, I don't understand the reason

    No you didn't. See comments at end.

    > behind this error. I can get it to work fine by just replacing the
    > DB_Disconnect() call in Misc.pm with &My::Misc::DB_Disconnect(), but
    DB------------------------------------------^^^^

    > that seems like a kludge, and I'd like to get a better understanding of
    > what's going on. :-)
    ....
    > ----- ~/test.pl ---------------------------------
    > #!/usr/bin/perl -w
    >
    > use strict;
    > use My::DB;
    > use My::Misc;
    >
    > my $dbh = DB_Connect();
    > SafeError($dbh, '/dev/null is full!');
    >
    >
    > ----- ~/My/DB.pm --------------------------------
    > # Database functions
    > package My::DB;
    >
    > use strict;
    > use Exporter;
    > use My::SOAP; # XXX this line causes the problem
    > use vars qw(@ISA @EXPORT);
    > @ISA = ('Exporter');
    > @EXPORT = qw(DB_Connect DB_Disconnect);
    >
    > sub DB_Connect {
    > # stub function, always returns true
    > my $dbh = 1;
    > return ($dbh);
    > }
    >
    > sub DB_Disconnect {
    > # stub function, always returns true
    > my ($dbh) = @_;
    > return (1);
    > }
    >
    > 1;
    >
    >
    > ----- ~/My/Misc.pm ------------------------------
    > # Miscellaneous functions (error handling, logging, untainting, etc.)
    > package My::Misc;
    >
    > use strict;
    > use Exporter;
    > use My::DB;
    > use vars qw(@ISA @EXPORT);
    > @ISA = ('Exporter');
    > @EXPORT = qw(SafeError);
    >
    > sub SafeError {
    > my ($dbh, $msg) = @_;
    >
    > print "Error: $msg\n";
    >
    > if ($dbh) {
    > print "Disconnecting from DB...\n";
    > DB_Disconnect($dbh);
    > }
    >
    > exit 1;
    > }
    >
    > 1;
    >
    >
    > ----- ~/My/SOAP.pm ------------------------------
    > # SOAP functions, for exchanging data with remote site
    > package My::SOAP;
    >
    > use strict;
    > use Exporter;
    > use My::Misc; # XXX this line causes the problem
    > use vars qw(@ISA @EXPORT);
    > @ISA = ('Exporter');
    > @EXPORT = qw(GetRemoteData);
    >
    > sub GetRemoteData {
    > # stub function, always returns true
    > return (1);
    > }
    >
    > 1;
    >
    >
    Note in:

    perldoc -f use

    that use() calls require(). Note in

    perldoc -f require

    that require() keeps track of which modules have been loaded in %INC (a
    global variable, always in package main). Therefore, when the use()
    function is called, it will do something only if that module has not
    already been loaded. So each module will be loaded exactly once.
    Subsequent calls to use() will not do anything. Therefore, when you use
    Exporter; to export your sub's, it only happens during the first use()
    of your module. Thus, the export of your sub names happens only the
    first time a given modules is use()'d.

    Basically, you are misusing (pun intended) the module mechanism in an
    attempt to simply define subs. If all you want is for all your subs to
    be present even though they are defined in other files, simply do() the
    other files, and forget modules and packages. When you properly use
    modules, you do not share subs (in modules, properly called methods).

    From the docs for Exporter:

    "Do not export method names!

    Do not export anything else by default without a good reason!

    Exports pollute the namespace of the module user. If you must
    export try
    to use @EXPORT_OK in preference to @EXPORT and avoid short or common
    symbol names to reduce the risk of name clashes."

    You are trying to use use() wrong. Read up on the various
    object-oriented docs and buy "Object Oriented Perl" and read it.

    --
    Bob Walton

    Bob Walton Guest

  4. #3

    Default Re: "Undefined subroutine" error (but it's defined, I think?)

    Bob Walton (bwalton@rochester.rr.com) wrote on MMMDCXXX September
    MCMXCIII in <URL:news:3F357BE8.1080704@rochester.rr.com>:
    ``
    `` Note in:
    ``
    `` perldoc -f use
    ``
    `` that use() calls require(). Note in
    ``
    `` perldoc -f require
    ``
    `` that require() keeps track of which modules have been loaded in %INC (a
    `` global variable, always in package main). Therefore, when the use()
    `` function is called, it will do something only if that module has not
    `` already been loaded. So each module will be loaded exactly once.
    `` Subsequent calls to use() will not do anything. Therefore, when you use
    `` Exporter; to export your sub's, it only happens during the first use()
    `` of your module. Thus, the export of your sub names happens only the
    `` first time a given modules is use()'d.

    That's not quite true. Yes, a module is *COMPILED* only once using
    this mechanism. But importing is done via the import() routine, which
    is called for each time "use" appears.

    If things happened as you discribe, one could use only one constant
    in each program, you could use 'strict' in only one module, etc, etc.


    `` Basically, you are misusing (pun intended) the module mechanism in an
    `` attempt to simply define subs. If all you want is for all your subs to
    `` be present even though they are defined in other files, simply do() the
    `` other files, and forget modules and packages. When you properly use
    `` modules, you do not share subs (in modules, properly called methods).
    ``
    `` From the docs for Exporter:
    ``
    `` "Do not export method names!
    ``
    `` Do not export anything else by default without a good reason!
    ``
    `` Exports pollute the namespace of the module user. If you must
    `` export try
    `` to use @EXPORT_OK in preference to @EXPORT and avoid short or common
    `` symbol names to reduce the risk of name clashes."
    ``
    `` You are trying to use use() wrong. Read up on the various
    `` object-oriented docs and buy "Object Oriented Perl" and read it.


    Where do object come in? The OP isn't using OO programming (and rightly so).


    Abigail
    --
    $" = "/"; split $, => eval join "+" => 1 .. 7;
    *{"@_"} = sub {foreach (sort keys %_) {print "$_ $_{$_} "}};
    %{"@_"} = %_ = (Just => another => Perl => Hacker); &{%{%_}};
    Abigail Guest

  5. #4

    Default Re: "Undefined subroutine" error (but it's defined, I think?)

    In article <3F357BE8.1080704@rochester.rr.com>, Bob Walton wrote:
    >> even though I made sure the caller (here Misc.pm) had imported all the
    >> functions of the other module. Hence, I don't understand the reason
    >
    > No you didn't. See comments at end.
    Alright, I went and spent some intimate time with 'man perlmod', 'man
    perlmodlib', 'man Exporter', 'perldoc use', 'perldoc require', 'perldoc
    do', and all their friends... :-)

    But none of those explain why the 'use DB;' line in Misc.pm is not
    importing the functions in the @EXPORT of DB.pm. The only way I can
    get this to work right is either by fully qualifying the function
    name (&My:DB:DB_Disconnect) or by inserting the line 'import My::DB;'
    somewhere in the My::Misc::SafeError sub. But adding the import line
    outside that scope doesn't work. That's what I don't understand. That
    sub belongs to the My::Misc package, so why doesn't it honor the pragmas
    in that package?

    And to make it even more confusing, in the 'real' modules (not the
    skeleton ones I listed previously) there are some subs that do honor the
    package pragmas, and some that don't. In both cases I'm talking about
    subs in the same package making identical calls to the same function in
    another package. Frex, in My::DB, several subs call My::Misc::GetDate,
    and in some cases I have to fully qualify it, and in some cases I don't.
    I can't seem to find a pattern though. :-(
    > Note in:
    >
    > perldoc -f use
    >
    > that use() calls require(). Note in
    >
    > perldoc -f require
    >
    > that require() keeps track of which modules have been loaded in %INC (a
    > global variable, always in package main). Therefore, when the use()
    > function is called, it will do something only if that module has not
    > already been loaded. So each module will be loaded exactly once.
    > Subsequent calls to use() will not do anything. Therefore, when you use
    > Exporter; to export your sub's, it only happens during the first use()
    > of your module. Thus, the export of your sub names happens only the
    > first time a given modules is use()'d.
    I rather like having everything exported as soon as possible. It's a
    mod_perl app, with all the modules preloaded by startup.pl, to avoid as
    many delays as possibly...

    I'm not sure what difference it makes that %INC is a global var though.
    That shouldn't negatively affect My::Misc, as the 'use DB;' line would
    just cause the 'require' step to be skipped and simply go on to import
    the @EXPORT subs in My::DB from the copy already in memory, right?
    > Basically, you are misusing (pun intended) the module mechanism in an
    > attempt to simply define subs. If all you want is for all your subs to
    > be present even though they are defined in other files, simply do() the
    > other files, and forget modules and packages. When you properly use
    > modules, you do not share subs (in modules, properly called methods).
    Well I only have a rudimentary understanding of OO Perl (having read the
    introductory OO chapter in Advanced Perl Programming--which incidentally
    I found easier to follow than the stuff in the camel book), so I'm not
    quite ready to take the plunge yet. And besides, I've already got well
    over 10,000 lines of procedural code that I have to finish testing ASAP,
    so there's no time to start tearing things up. Maybe next project... :-)

    Still, I don't think it's a total waste to use modules for just plain
    old procedural code. I make judicious use of @EXPORT, @EXPORT_OK and
    use specific sub names based on the package name to avoid namespace
    clashes (frex, DB_Disconnect and other DB_ prefixed subs are in the
    My::DB package).

    valerian@no.valid.email Guest

  6. #5

    Default Re: "Undefined subroutine" error (but it's defined, I think?)

    [email]valerian2@hotpop.com[/email] wrote:
    [snip]
    > package My::DB;
    >
    > use strict;
    > use Exporter;
    > use My::SOAP; # XXX this line causes the problem
    > use vars qw(@ISA @EXPORT);
    > @ISA = ('Exporter');
    > @EXPORT = qw(DB_Connect DB_Disconnect);
    [snip function definitions]
    > # SOAP functions, for exchanging data with remote site
    > package My::SOAP;
    >
    > use strict;
    > use Exporter;
    > use My::Misc; # XXX this line causes the problem
    > use vars qw(@ISA @EXPORT);
    > @ISA = ('Exporter');
    > @EXPORT = qw(GetRemoteData);
    [snip function definition]

    Remember that 'use' happens at compile time, and @EXPORT= and @ISA=
    happen at run time.

    If you changed the beginnings of these three modules to:

    package My::DB;
    BEGIN {
    require Exporter;
    @ISA = qw(Exporter);
    @EXPORT = qw(DB_Connect DB_Disconnect);
    }
    use strict;
    use My::SOAP;

    And:

    package My::SOAP;
    BEGIN {
    require Exporter;
    @ISA = qw(Exporter);
    @EXPORT = qw(GetRemoteData);
    }
    use strict;
    use My::Misc

    And:

    package My::Misc;
    BEGIN {
    require Exporter;
    @ISA = qw(Exporter);
    @EXPORT = qw(SafeError);
    }
    use strict;
    use My::DB;

    Then it *should* work. [but since this code is untested, don't sue me
    if it doesn't.]

    --
    $a=24;split//,240513;s/\B/ => /for@@=qw(ac ab bc ba cb ca
    );{push(@b,$a),($a-=6)^=1 for 2..$a/6x--$|;print "$@[$a%6
    ]\n";((6<=($a-=6))?$a+=$_[$a%6]-$a%6:($a=pop @b))&&redo;}
    Benjamin Goldberg Guest

  7. #6

    Default Re: "Undefined subroutine" error (but it's defined, I think?)

    Benjamin Goldberg wrote:
    > [email]valerian2@hotpop.com[/email] wrote:
    > [snip]
    >
    >>package My::DB;
    >>
    >>use strict;
    >>use Exporter;
    >>use My::SOAP; # XXX this line causes the problem
    >>use vars qw(@ISA @EXPORT);
    >>@ISA = ('Exporter');
    >>@EXPORT = qw(DB_Connect DB_Disconnect);
    >>
    > [snip function definitions]
    >
    >># SOAP functions, for exchanging data with remote site
    >>package My::SOAP;
    >>
    >>use strict;
    >>use Exporter;
    >>use My::Misc; # XXX this line causes the problem
    >>use vars qw(@ISA @EXPORT);
    >>@ISA = ('Exporter');
    >>@EXPORT = qw(GetRemoteData);
    >>
    > [snip function definition]
    >
    > Remember that 'use' happens at compile time, and @EXPORT= and @ISA=
    > happen at run time.
    >
    > If you changed the beginnings of these three modules to:
    >
    > package My::DB;
    > BEGIN {
    > require Exporter;
    > @ISA = qw(Exporter);
    > @EXPORT = qw(DB_Connect DB_Disconnect);
    > }
    > use strict;
    > use My::SOAP;
    >
    > And:
    >
    > package My::SOAP;
    > BEGIN {
    > require Exporter;
    > @ISA = qw(Exporter);
    > @EXPORT = qw(GetRemoteData);
    > }
    > use strict;
    > use My::Misc
    >
    > And:
    >
    > package My::Misc;
    > BEGIN {
    > require Exporter;
    > @ISA = qw(Exporter);
    > @EXPORT = qw(SafeError);
    > }
    > use strict;
    > use My::DB;
    >
    > Then it *should* work. [but since this code is untested, don't sue me
    > if it doesn't.]

    Hmmmmm...yes, that does make it work. But I don't think the explanation
    is quite right. @EXPORT and @ISA *do* get defined at compile time,
    because the use() is the same as BEGIN{require module;import module}.
    The require() do'es the module code, including the assignments to
    @EXPORT and @ISA, at compile time. And the import method runs at
    compile time. The do() from the use() will run before the import, so
    everything should be defined. BUT some of the modules are use'd twice,
    and the second time the do() is not performed. In the package of the
    second call to use(), @EXPORT and @ISA don't get defined, so the routine
    doesn't know it is an Exporter, so Exporter's import doesn't get called.
    And the @EXPORT list doesn't get exported. Your solution works
    because @ISA and @EXPORT are defined in the package namespace before the
    use() is called. I think that is right because I traced through it with
    the debugger with BEGIN{$DB::single=1} to debug the stuff executed at
    compile time.

    Pretty hairy. My apologies for my incorrect first analysis, as pointed
    out by Abigail and valerian2.
    --
    Bob Walton

    Bob Walton Guest

Posting Permissions

  • You may not post new threads
  • You may post replies
  • You may not post attachments
  • You may not edit your posts

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139