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

I have an issue I'm debugging that is making me question my somewhat limited understanding of method resolution. The below Pl and Pattern classes are Moose classes utilizing MooseX::Types and MooseX::Params::Validate.

First, here's the line where things go haywire in the debugger (apologies for width):

DB<18> . Program::Plist::Pl::_create_pattern_obj(/nfs/pdx/disks/nehalem.pde.077 +/projects/lib/Program-Plist-Pl/lib/Program/Plist/Pl.pm:62): 62: my $pattern_obj = Program::Plist::Pl::Pattern->new(name => + $name, 63: mask_da +ta => $mask_data, 64: tags => + $tags);

This call should first check the Program::Plist::Pl::Pattern symbol table for a new entry. Here's our symbol table:

DB<3> print Dumper(\%Program::Plist::Pl::Pattern::); $VAR1 = { 'import' => *Program::Plist::Pl::Pattern::import, 'meta' => *Program::Plist::Pl::Pattern::meta, 'ISA' => *Program::Plist::Pl::Pattern::ISA, 'BEGIN' => *Program::Plist::Pl::Pattern::BEGIN, 'isa' => *Program::Plist::Pl::Pattern::isa };

Ok, no new entry here. Next step should be checking Pattern's @ISA for parents:

DB<4> print Dumper \@Program::Plist::Pl::Pattern::ISA $VAR1 = [ 'Moose::Object' ];

We have Moose::Object as a parent. Next step should be checking to see if this parent class has a 'new' entry in its symbol table (some entries deleted for readability):

DB<6> print Dumper \%Moose::Object:: $VAR1 = { '__mx_is_compiled' => *Moose::Object::__mx_is_compiled, 'new' => *Moose::Object::new, 'DOES' => *Moose::Object::DOES };

Ok, it appears that we have a new entry for Moose::Object. At this point, I would assume that &Moose::Object::new(@args) would be called. I have a locally modified version of that library that prints args when called. Let's make certain it works:

DB<14> &Moose::Object::new('arg1'); MOOSE->NEW CALLED WITH ARGS (arg1) Can't locate object method "BUILDARGS" via package "arg1" (perhaps you + forgot to load "arg1"?) at /nfs/pdx/disks/nehalem.pde.077/debug/Moos +e/Object.pm line 25, <$fh> line 8.

Ok, verified that my code does print when the Moose::Object::new method is called. Let's execute our problem line and see what happens. First, our line is:

DB<1> c Program::Plist::Pl::_create_pattern_obj(/nfs/pdx/disks/nehalem.pde.077 +/projects/lib/Program-Plist-Pl/lib/Program/Plist/Pl.pm:62): 62: my $pattern_obj = Program::Plist::Pl::Pattern->new(name => + $name, 63: mask_da +ta => $mask_data, 64: tags => + $tags);

And issuing a single step command to the debugger results in this:

DB<18> s MooseX::Types::EXPORTED_TYPE_CONSTRAINT=CODE(0x1ec2ca8)(/nfs/pdx/disks +/nehalem.pde.077/debug/MooseX/Types.pm:386): 386: my $type_constraint = $class->create_base_type_constra +int($name);

How did I get to MooseX::Types::EXPORTED_TYPE_CONSTRAINT? I don't see the output for Moose::Object::new at all, meaning I didn't get there. How have I short circuited the symbol table lookups to get to this code? Is my understanding of how a method is found wrong? My inability to trace this code has made debugging my issue very difficult.

It would appear this code is being called to deal with the arguments to the Pattern->new call, but I see no functions in the arguments to the call.

Replies are listed 'Best First'.
Re: Moose, @ISA and method resolution
by stvn (Monsignor) on Jan 11, 2011 at 01:12 UTC

    To start with, you did not explain what the actual you are getting is, that would be very helpful. It would also be helpful if you could paste the source for the Program::Plist::Pl::Pattern class as well as the Program::Plist::Pl::_create_pattern_obj code. Without that all we can do is guess.

    How did I get to MooseX::Types::EXPORTED_TYPE_CONSTRAINT?

    No idea, would help if we could see the code.

    I don't see the output for Moose::Object::new at all, meaning I didn't get there. How have I short circuited the symbol table lookups to get to this code? Is my understanding of how a method is found wrong?

    No, your understanding is correct, there is something else going on here which we might be able to diagnose if we could see the code :)

    It would appear this code is being called to deal with the arguments to the Pattern->new call, but I see no functions in the arguments to the call.

    It doesn't really make sense that it would, unless you are doing something funky in Program::Plist::Pl::Pattern::new, however it could also be Moose::Object::new trying to validate against the type constraint in one of your attriubtes. Again, seeing the code for Program::Plist::Pl::Pattern would help a TON.

    And of course, make sure you are up to date on all modules (Moose, MooseX::Types, and MooseX::Params::Validate) if they are not all up to date you may be running into compat issues between them.

    -stvn
Re: Moose, @ISA and method resolution
by tj_thompson (Monk) on Jan 11, 2011 at 05:19 UTC

    First off, many thanks for taking the time to answer so many questions about Moose Stevan. It's appreciated by all of us. So a big thanks from me.

    Next, I am happy to say that after a nice 6 or more day learning experience (Yeah, that's embarrassing) I've finally determined what's going on. I finally boiled this down to a minimal test case and realized that the code isn't doing what I think the code is doing. MO=Deparse showed that instead of calling Program::Plist::Pl::Pattern->new, I was calling Pattern()->new().

    As it turns out, I have a MooseX::Types definition for a Pattern type. At the top of the Pl.pm file, I use Program::Types qw(Pattern) Which means I have now imported a subroutine into my package that has the SAME fully qualified name as my package I'm trying to instance. So when I said Program::Plist::Pl::Pattern->new(), Perl thought I wanted to call the Pattern subroutine &Program::Plist::Pl::Pattern()(which is why I'm off in MooseX::Types land in the debugger) and then call the new method of the result.

    I'll post some code tidbits of my mistake here tomorrow in the hope it may help someone else not make the same mistake :)

      Excellent, I am glad to hear you solved it. I will point out again that if you had posted the code to the Pattern class, we probably would have been able to save you those 6 days of debugging :)

      This exact issue is why I do not use MooseX::Types and probably never will (and why it has not become part of Moose core). While it is nice to have compile time checking of type names, it is at the expense of twisting perl's arm and trying to make types look like barewords. Some magic is just not worth it.

      -stvn
      One solution, though it looks ugly, is to call Program::Plist::Pl::Pattern::->new(). This disambiguates between the package and any possible function of the same name as the package.

        This is quite true, and another reason why MooseX::Types won't get into core Moose. In my opinion it is unacceptable to put the burden of change on the user like this.

        -stvn