Namespace resolution question: I'm somewhat puzzled

D

David Squire

Hi,

I am reorganizing some of my Perl code to place modules where they can
be found via environment variable PERL5LIB. Some namespace issues are
not working as I would have expected, and I have not been able to find a
nice piece of documentation to explain this.

For example, consider this scenario:

I have directory MyLib (present in $PERL5LIB), which contains two
subdirectories Foo and Bar. Foo contains a module FooTools.pm, and Bar
contains BarTools.pm, i.e. the files MyLib/Foo/FooTools.pm and
MyLib/Bar/BarTools.pm both exist.

In FooTools.pm, I have:

use Bar::BarTools;

Later in FooTools.pm, I want to use a function func() that lives in
BarTools.pm. I expected this to work:

Bar::BarTools::func();

It did not, telling me that it could not find the function, though it is
certainly present in MyLib/Bar/BarTools.pm. This, however, *did* work:

BarTools::func();

Why is it that 'Bar' must be present in the 'use' statement (as I would
in fact expect), but cannot be present when I call the function? I would
have expected a fully qualified name always to work.

What would happen if there were a module BarTools in Foo, and I had done
this in FooTools.pm:

use Bar::BarTools;
use Foo::BarTools;
....
BarTools::func();

?

Would Bar::BarTools::func() work only if there were such a conflict?

Any help or pointers much appreciated.

Regards,

David
 
E

ednotover

David said:
Later in FooTools.pm, I want to use a function func() that lives in
BarTools.pm. I expected this to work:

Bar::BarTools::func();

It did not, telling me that it could not find the function, though it is
certainly present in MyLib/Bar/BarTools.pm. This, however, *did* work:

BarTools::func();

Does Bar/BarTools.pm define itself as:

package BarTools;

or is it using (as it sounds like you want):

package Bar::BarTools;

My guess is you're using the former, but should be using the latter.
Ed
 
P

Paul Lalli

David said:
I am reorganizing some of my Perl code to place modules where they can
be found via environment variable PERL5LIB. Some namespace issues are
not working as I would have expected, and I have not been able to find a
nice piece of documentation to explain this.

For example, consider this scenario:

I have directory MyLib (present in $PERL5LIB), which contains two
subdirectories Foo and Bar. Foo contains a module FooTools.pm, and Bar
contains BarTools.pm, i.e. the files MyLib/Foo/FooTools.pm and
MyLib/Bar/BarTools.pm both exist.

In FooTools.pm, I have:

use Bar::BarTools;

This tells Perl to load the code that is present in the *file*
Bar/BarTools.pm
Later in FooTools.pm, I want to use a function func() that lives in
BarTools.pm. I expected this to work:

Bar::BarTools::func();

This tells Perl to call the subroutine func() in the *package*
Bar::BarTools.
It did not, telling me that it could not find the function, though it is
certainly present in MyLib/Bar/BarTools.pm. This, however, *did* work:

BarTools::func();

This tells Perl to call the subroutine fun() in the *package* BarTools.

You have only given (and I assume therefore, realized) half of the
relevant information. The physical location of the files in question
is only relevant for the 'use' statement. It is the content of those
files that determines the packages

If you want func() to live in the package Bar::BarTools, then
BarTools.pm must declare:
package Bar::BarTools;

Judging by your stated results, I conclude that instead, BarTools.pm
declares:
package BarTools;
Why is it that 'Bar' must be present in the 'use' statement (as I would
in fact expect), but cannot be present when I call the function?

Because 'use' is looking for the physical location of files. The call
to the function is looking for what packages the given function is
contained in.
I would have expected a fully qualified name always to work.

It does... it just has to be the *right* fully qualified name. :)
What would happen if there were a module BarTools in Foo, and I had done
this in FooTools.pm:

use Bar::BarTools;
use Foo::BarTools;
...
BarTools::func();

?

Would Bar::BarTools::func() work only if there were such a conflict?

Again, it's not possible to answer this question with only half the
information. The "fully qualified" name of a function (or global
variable) is defined by it's containing *package*, not by the the
physical location of the file.

Hope that helps,
Paul Lalli
 
M

Marcin Kasperski

use Bar::BarTools;

Later in FooTools.pm, I want to use a function func() that lives in
BarTools.pm. I expected this to work:

Bar::BarTools::func();

It did not, telling me that it could not find the function, though it
is certainly present in MyLib/Bar/BarTools.pm. This, however, *did*
work:

BarTools::func();

I strongly suspect that you incorrectly declared package in
BarTools. Probably you have there 'package BarTools', while you should
have 'package Bar::BarTools'.


Directories are used by perl for searching for the FILES to
load. Then, package directives decide what MODULES are the functions
present in the file loaded to.

You can even do dirty tricks, like putting a few different packages
into single file.
 
D

David Squire

Does Bar/BarTools.pm define itself as:

package BarTools;

or is it using (as it sounds like you want):

package Bar::BarTools;

My guess is you're using the former, but should be using the latter.

Thanks for this. I was thinking more about this after I posted the
question, and came to the conclusion that this must be the case.

I do think that this introduces some slight ugliness, as now the package
declaration in a file is dependent on its location in the file system,
rather than that being implicit. If I move the file, I must change the
package line... but then I would already have to change all the "use"
statements that refer to it, so I guess this is a small cost.

Thanks,

David
 
U

Uri Guttman

DS> I do think that this introduces some slight ugliness, as now the
DS> package declaration in a file is dependent on its location in the
DS> file system, rather than that being implicit. If I move the file,
DS> I must change the package line... but then I would already have to
DS> change all the "use" statements that refer to it, so I guess this
DS> is a small cost.

you can still move the file around and not change the package name as
long as you keep the last part of the path matching the package
name. the earlier part of the path can be changed but it had to be in
perl's search path (settable via %ENV, -I, @INC and use lib). and as for
why you would be moving a module around, i can't say.

this brings up some rules about package names and files. package names
and perl module location are completely independent from each other. you
can have 1 file with multiple package spaces and multiple files which
have the same package spaces. both situations are useful (and i have
done both). if you want full use sematics of calling import then the
name passed to use must match some package space in some loaded file. in
fact it doesn't even have to be in the same file that use loaded (note
the separation note). you could use Foo and Foo.pm will load Bar.pm
which has package Foo in it and it supplies an import sub (its own or
inherited from Exporter) and it will work just fine. not that i would
recommend that style.

uri
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top