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

Hello monks.

I suppose recursive 'uses' should be avoided in general cases, but still, I'd like to understand what's going on with this simple code: A1 and A2 are using C, which uses A2. Warning and strict are used in all files.

File A1.pm

package A1; use A2; use C; sub functionA { print "In A1: ".C::TYPE->{VEG}."\n"; A2::functionA(); }

File A2.pm

package A2; use C; sub functionA { print "In A2: ".C::TYPE->{VEG}."\n"; }

File C.pm

package C; use A2; use constant { TYPE => { FRUIT => 1, VEG => 2, MEAT => 3, }, };

Now we can test:

use A2; A2::functionA(); # prints "In A2: 2"

and

use A1; A1::functionA(); # prints "In A1: 2\nIn A2: 2"

Right. But if we inverse the order of 'use' in A1.pm, so C is 'used' before A2, the second test leads to a non-understanding of external constant TYPE: "Can't use bareword ("C::TYPE") as a HASH ref while "strict refs" in use at A2.pm line 7". Why so?

Question 2: If we keep this order, I can fix the problem by calling in A2.pm "C->TYPE->{VEG}" instead of "C::TYPE->{VEG}". Enlightenments welcome! : )

Cheers.

Locinus (perl v5.12.3 built for MSWin32-x86-multi-thread)

Replies are listed 'Best First'.
Re: Behaviour on recursive use
by tobyink (Canon) on Mar 05, 2014 at 21:53 UTC

    It's not a problem from perl's perspective, but behaviour in the case of circular requires can sometimes be a little unintuitive:

    # foo.pm package foo; use bar; sub import { printf("%s loaded foo\n", scalar caller) } 1;
    # bar.pm package bar; use foo; sub import { printf("%s loaded bar\n", scalar caller) } 1;
    # script.pl use foo;

    Running the script, generates the following output:

    foo loaded bar main loaded foo

    Did you expect to see bar loaded foo somewhere in that output?

    With careful consideration of compile time versus runtime, etc, etc, you'll realise why that line was not output, and that this is proper and documented behaviour. Just not necessarily very intuitive.

    use Moops; class Cow :rw { has name => (default => 'Ermintrude') }; say Cow->new->name

      Fair enough. Thank you for leading me in the way.

      So, according to the imports order, the compiler will or won't load the different variables/subs in the right order, so that in my example, we have :

      ========= OK test : load A1 -> load A2 -> load C (but constant TYPE is not loaded already) -> not load A2 (already 'used') -> load constant TYPE ========= KO test : load A1 -> load C (but constant TYPE is not loaded already) -> load A2 -> not load C (already 'used') -> fail because constant TYPE is not loaded

      Is that right?

      Ok. What about the "C->TYPE" vs "C::TYPE", the first being the one that always works whatever the 'use' order. Is that a "runtime" vs "compile time", as you pointed out?

      Cheers.
Re: Behaviour on recursive use
by Laurent_R (Canon) on Mar 05, 2014 at 19:49 UTC

    I suppose recursive 'uses' should be avoided in general cases...

    Well, it can't be avoided in many cases. Numerous modules use other modules, so that you can end up with a fairly complicated dependency tree. The good thing about use is that if the dependency tree calls the same modules several times, the module will be loaded only once. Having said that, you obviously have to be a bit careful with the order in which you load modules, and it can sometimes be an headache if the dependency tree is large.