I'm still somewhat confused. If the problem is due to the fact that the filename and the package name don't match, then why does the following not also give an error, given that I'm loading Foo the same (incorrect) way:
#!/tool/bin/perl -w
use strict;
use lib '/home/user/perl_modules/lib/perl5';
use My::Foo;
my $new_foo = Foo->new();
I thought that generally speaking, whatever prefixed the :: of a module name (e.g. Foo) was used to denote directories that the module's file (Foo.pm) was within, relative to whatever was in my @INC. In my example above, the /home/user/perl_modules/lib/perl5 folder contains the 'My' folder containing my own personal modules (such as Foo.pm), but it also contains all of the folders of modules I downloaded from CPAN (it's a local perl installation), e.g.:
/home/user/perl_modules/lib/perl5
My/
CGI/
Devel/
Pod/
...
and so on.
Are you saying that instead of what I did above, I should instead do the following:
use lib '/home/user/perl_modules/lib/perl5';
use lib '/home/user/perl_modules/lib/perl5/My';
use Foo;
Or am I misunderstanding?
| [reply] [d/l] [select] |
Here's the thing... Package name and filesystem path have (almost1) no intrinsic connection at all. The only reason they're normally the same is because of convention. But you should absolutely follow this convention because, even though Perl can handle it without problems, it easily becomes very, very confusing for humans trying to use the code, as your post here illustrates.
I suspect the reason you're not quite seeing the significance of the distinction is that, in this case, your package name and filesystem path are almost, but not quite, the same, so it's easy to gloss over that difference in your head. So let's rewrite things a bit to make it more obvious. In a file at My/Bar.pm, put
package Xyzzy;
sub say_it {
print "It works!";
}
Now, in your code, you load this file with use My::Bar; but there is no package named My::Bar, or even a package named Bar. The package is named Xyzzy, so you must call the sub with Xyzzy::say_it (or Xyzzy->say_it if you prefer, since it will just ignore all parameters passed anyhow).
If you move the module file to Some/Random/Place.pm, you will then load it with use Some::Random::Place;, but the package inside is still package Xyzzy, so you still have to call the code with Xyzzy::say_it, not Some::Random::Place::say_it. The path you use the module at and the package within the module are two separate things.
1 There is one exception. The one and only time that Perl cares whether the path and the package name match up is when you export symbols. This is because use Whatever; is equivalent to require Whatever; Whatever->import(); so, if the file Whatever.pm contains package Something::Else, and Something::Else exports symbols, that won't work because the use will implicitly call Whatever->import() (which doesn't exist) and not Something::Else->import(). | [reply] [d/l] [select] |
Thanks for the additional information, this is starting to make more sense now. Is it correct that in the context of a "use" statement (example: use My::Foo), the :: effectively represent a filesystem directory separator character (e.g. '/' in Linux), the last word with a ".pm" appended to it represents the module's filename, and this path (My::Foo, e.g. /My/Foo.pm) is then appended to each base path in @INC to determine where Perl will search for the listed module?
If I'm understanding everything correctly, my original example is failing because the use My::Foo 1.0 statement is using My::Foo as a search path to find My/Foo.pm (relative to /home/user/perl_modules/lib/perl5) but it is also treating My::Foo as a package name to look for a version variable My::Foo::$VERSION. The only way both of these can be correct is if the package name matches the exact name specified to use the module. I was able to fix everything by either doing this:
use lib '/home/user/perl_modules/lib/perl5/My';
use Foo 1.0;
Or by renaming the package to My::Foo and then updating the code references accordingly.
Also after I created the My/Bar.pm file as written in your post and then another file to "use My::Bar" and then call the Xyzzy->say_it function, I received the following error:
My/Bar.pm did not return a true value at ./bar_test.pl line 4.
BEGIN failed--compilation aborted at ./bar_test.pl line 4.
I was able to fix this by adding a "1;" to the end of Bar.pm. Do all packages need to end with "1;"?
> The package is named Xyzzy, so you must call the sub with Xyzzy::say_it (or Xyzzy->say_it if you prefer, since it will just ignore all parameters passed anyhow).
Can you elaborate on this a little bit? What exactly is the difference between calling say_it with :: vs ->?
| [reply] [d/l] [select] |
#!/tool/bin/perl -w
use strict;
use lib '/home/user/perl_modules/lib/perl5/My';
use Xyzzy;
say_it();
Now the package name matches the file name. Running this code gives the following error:
Undefined subroutine &main::say_it called at ./xyzzy_version_test.pl l
+ine 6.
It seems that the package name Xyzzy is still explicitly required in this case to call the say_it function even though the package name now matches the filename. After doing some searching, I found that adding the following to My/Xyzzy.pm allows the above call to say_it() (without the Xyzzy->) to work:
use Exporter qw(import);
our @EXPORT = qw(say_it);
our @EXPORT_OK = qw();
My question is: are the above 3 lines of code that I added to My/Xyzzy.pm (and using qw() to reference specific subroutines in a package, e.g. use Xyzzy qw(say_it);, had I included say_it in the EXPORT_OK list rather than the EXPORT list) only used to prevent the user from having to prefix every call to a exported subroutine with Package-> every time, or do they serve other purposes?
| [reply] [d/l] [select] |