Re^2: error for undefined function that's been imported
by argv (Pilgrim) on Aug 15, 2005 at 11:34 UTC
|
Sure-- this stuff works ok almost all the time. The sporadic behavior is one that is hard to describe, really. But, to answer your question, here's some code: (note the inclusion of the Register module)
MyUserProfile.pm
package MyUserProfile;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT = qw(ProfileGet ProfileSave ProfileEdit ProfileUpdate
ProfileFix ProfileExtract ProfileFixContactInf
+o
$user_data $contact_strings, @contact_info);
our $VERSION = 1.00;
use MyErrors;
use CGI;
use Register qw(PrintTemplate RegisterChange RegisterAcctPath Register
+SetupUser
EDIT_PROFILE VIEW_IMAGES read_user_db);
use MyUtils qw(:DEFAULT);
Now, here's a snippet from Register:
Register.pm
[...]
use MyUserProfile qw(:DEFAULT);
[...sometime later in some function...]
my $acct_data = MyUserProfile::ProfileGet($acct);
[...]
Even though ProfileGet() is properly exported, I can't just call it without perl complaining about Register.pm calling an undefined function. I have to use it in the form above to get it to shup up (and work). But this is the frustrating part: it's not ALWAYS the case. Sometimes, functions can be called directly, whereas other times, maybe not. Maybe there's a pattern to when it works and when it doesn't, but suffice to say, I can't see it (hence, the appearance of randomness).
Could the inter-dependence on the modules to one another be causing this, or point to the direction of the problem?
| [reply] [d/l] [select] |
|
|
What you have should, on the surface, be working.
:DEFAULT should be doing what it says on the tin, but try explicitly naming the subs you wish to import, and see if this works.
One point that occurs to me is that Register.pm could be switching namespaces - with further package declarations. If this is the case, the use will import the subs once - into the package namespace of its context. This is why you need to declare your package first before using Exporter style modules. OO modules don't suffer from this problem as they use a different technique for getting to the namespace.
If you've still got a problem, I suggest dumping out the key stashes (symbol table hashes) after BEGIN has happened, to see whether Exporter has aliased the subs properly. One way to do this is with the debugger (perl -d) - run it up and issue the command:
DB<1> x %Register::
and see if the sub names appear.
Alternatively, add the following lines to your main program: use Data::Dumper;
print Dumper \%Register::;
--
Oh Lord, won’t you burn me a Knoppix CD ?
My friends all rate Windows, I must disagree.
Your powers of persuasion will set them all free,
So oh Lord, won’t you burn me a Knoppix CD ? (Missquoting Janis Joplin)
| [reply] [d/l] |
|
|
As I'd pointed out before, I suspected that there was a namespace problem, and your suggestions are good for determining if that's the case. The problem is, what do I do if I make that determination? You passively mentioned this:
This is why you need to declare your package first before using Exporter style modules.
Can you elaborate on this? I assume this is something I didn't do, and I don't quite understand how to change the code to meet this requirement. You so quickly mentioned, almost as an aside, that it sounds as though you don't suspect it to be an explanation for the behavior.
| [reply] |
|
|
|
|
|
|
|
Could the inter-dependence on the modules to one another be causing this
This is all a guess, but...
Yes. Specifically, the subs you're trying to import (and the @EXPORT list, and I think &import itself for that matter) don't actually exist when import is called. Since use effectively runs inside a BEGIN block, the use Register line interrupts compilation of MyUserProfile to execute Register.pm. Then while compiling Register, the use MyUserProfile line will first attempt to require MyUserProfile, which is a no-op since it is already in %INC even though it hasn't finished compiling, and then it will import MyUserProfile, which is also a no-op since nothing in that package is defined yet (except what was exported to it by earlier use statements).
By the way, that's for the case where a script tries to use MyUserProfile without first doing a use Register. It looks like there are similar problems (with different functions) going the other way. Hence it "seems to happen in parts of the code that I'm NOT working on".
| [reply] [d/l] [select] |
|
|
our %EXPORT_TAGS =
( :DEFAULT => [ qw( ProfileGet ProfileSave ProfileEdit ) ] );
Update: Thanks to ysth and rinceWind for the whack with the clue by four.
| [reply] [d/l] |
|
|
| [reply] |
|
|
Apparently this one is defined for you to be the contents of @EXPORT, see Exporter
--
Oh Lord, won’t you burn me a Knoppix CD ?
My friends all rate Windows, I must disagree.
Your powers of persuasion will set them all free,
So oh Lord, won’t you burn me a Knoppix CD ? (Missquoting Janis Joplin)
| [reply] |
|
|
I'm replying to my own posting to provide an update with a new observation. In my attempts to understand rinceWind's description of how use/import works by playing with the order of which packages are imported with use (and getting absolutely nowhere), I decided to re-order the use statements in the actual perl program itself--not in the modules. To my surprise (because I don't understand it), the problem magically went away. Yes, by merely swapping which package was included first, the error evaporated:
use MyUserProfile "ProfileGet";
use Register qw(PrintTemplate);
This works. Swap the two, and I get the undefined function error for MyUserProfile.pm. Problem is, this "solution" only happens to work with this perl script. I can write another that merely makes different calls to some other functions in these packages, and I'll get another "undefined function" error... which, again, can be fixed by--sigh--swapping the use statements in that perl script.
So, what I'm left with is a complete misunderstanding of how to generally avoid such a problem with any given perl script that imports these (and many other) packages (that I write). I've got a ton of routines in each package that all call routines into each other. I don't mind following the rules about order and precedence, but I either don't know what they are (I thought I did), or the speghetti just gets too tangled when module sizes (and quantities of them that use each other) exceeds a certain threshold.
| [reply] [d/l] [select] |
|
|
I'm not sure whether you've benefitted as much as you'd like from rincewind's discussion, but in my own (less than fully experienced) opinion, Bob9000's point is the more pertinent one. If I see a code base being built up with packages like this:
## file: SomeModule.pm ##
package SomeModule;
#...
use OtherModule;
#...
__END__
## file: OtherModule.pm ##
package OtherModule;
#...
use SomeModule;
#...
my first reaction is "don't do that", and my next reaction is "this is crying out desparately for refactoring".
Cross-references like that turn your code into a sort of "chicken-and-egg" problem -- if not in terms of actual compilation troubles, then at least in terms of ongoing maintenance. When someone else comes along to fix or add something, they have to go around in circles to track what the code is doing (and that "someone else" could very well be you, six months from now).
The main point of creating modules is to encapsulate things that are logically independent of other things. Having mutual dependencies among modules just defeats their purpose.
Look at the functions defined in "MyUserProfile.pm" that are called from "Register.pm", and likewise at those defined in the latter that are called from the former. If you can put these functions into one or more distinct modules, and have the two original modules use the new ones instead of using each other, things will be easier all around.
Ideally, this should lead you in the same direction that rincewind suggested: an OO design. If a current module is based on certain data being shared by its various subs, you have an obvious basis for making that into an object; if not, then just dividing up the subs a bit differently to eliminate module cross-dependencies should be fairly easy and sufficient, and will reduce incoherence in your code. | [reply] [d/l] |
|
|
The main point of creating modules is to encapsulate things that are logically independent of other things. Having mutual dependencies among modules just defeats their purpose.
While this is true, it's simplistic to think that just because something is encapsulated into its own module that it doesn't somehow rely on other modules that do entirely different things. This is the whole spirit of libraries, as opposed to objects and classes.
I'm sure I don't have to remind most of the readers here that there's nothing wrong or unusual about library functions that may call back and forth between themselves, nor is it always the case that one needs to build class hierarhcies just to have a series of independent functions that have no common ancestors to one another, but which are still separated into discrete files from one another because their abstraction paradigms are entirely different. While I'm a fan (and implementor) of object-oriented programming (I've written two books on the subject for ORA), I also know when not to use an elephant gun when all I want to kill is a mouse.
Surely, there must be a way in perl to have a series of modules that have variables and functions that can be exported and used by other modules, while also being able to import such from other modules, all without having the kind of mess I'm running into here. Given these set-backs, I can only assume that, perhaps, "use" and "module" are not the way to make generically exportable and inter-dependent library functions, but that some other method is perhaps more suited. Either that, or perl needs a way for a module to declare a function as type "no-really-I'm-global-and-this-time-I-mean-it."
| [reply] |