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

So I've been diving into Moose and I've learned a few things. One thing is that it brings some rigor to the code that I definitely like. Another thing is that debugging ranges from mildly annoying to torturously painful. I'm coming up with an error like below (added whitespace for an attempt at readability):


MooseX::Types::TypeDecorator->new was called with args (MooseX::Types::TypeDecorator,Program::Types::Pattern)
MooseX::Types::TypeDecorator->new was called with args (Program::Types::Pattern,name,pattern1,mask_data,,tags,HASH(0x1fb9eb8))

Argument cannot be 'name' at /nfs/pdx/disks/nehalem.pde.077/tmp/MooseX/Types/TypeDecorator.pm line 89

MooseX::Types::TypeDecorator::new('MooseX::Types::TypeDecorator=HASH(0x1fbe568)', 'name', 'pattern1', 'mask_data', '', 'tags', 'HASH(0x1fb9eb8)') called at /nfs/pdx/disks/nehalem.pde.077/projects/lib/Program-Plist-Pl/lib/Program/Plist/Pl.pm line 52

Program::Plist::Pl::_create_pattern_obj('Program::Plist::Pl=HASH(0x1f682d0)', 'pattern1', undef, undef) called at /nfs/pdx/disks/nehalem.pde.077/projects/lib/Program-Plist-Pl/lib/Program/Plist/Pl.pm line 74

Program::Plist::Pl::BUILD('Program::Plist::Pl=HASH(0x1f682d0)', 'HASH(0x1fbb328)') called at generated method (unknown origin) line 101

Program::Plist::Pl::new('Program::Plist::Pl', 'name', 'test_plist', 'parents', 'HASH(0x1fc8918)', 'external_pl_code', 'CODE(0x7bd990)', 'fh', 'GLOB(0x63d220)', ...) called at Program-Plist-Pl.t line 23


The first two lines are my own debug output placed into a local copy of MooseX::Types::TypeDecorator.pm. The remainder is the result of the error.

While I'd certainly be interested in what is causing this error (I've probably wasted a day looking over code), I'm more interested in how to debug MooseX in general.

Looking at the callstack above, I see the call from Program::Plist::Pl::_create_pattern_obj (which looks good from the arguments standpoint) and then suddenly an error from MooseX::Types::TypeDecorator->new. The first two lines show the problem. TypeDecorator->new seems to expect two arguments: A self reference like any oo call, and what appears to be a MooseX type object as the first argument. However, the failing ->new call seems to show there is no TypeDecorator self reference, and the arguments from the Program::Plist::Pl::_create_pattern_obj call seem to have been pushed to the argument list. Just in case it helps, the _create_pattern_obj call is a wrapper that slightly modifies the arguments and passes them to Program::Plist::Pl->new to get a Pl object. I've verified the underlying new call works fine with the same arguments it's receiving here when it's outside of this code.

First, I'd obviously like to know what's happening above. I didn't post code because there's too much, so I understand if there's not enough to go on here. More importantly, how does one debug into the above type of issue, or Moose in general? I'm typically a primitive instrumentation type of debugger, but the above problem is stemming from code that both may not even exist to instrument (created by Moose based on my class) and is not showing up in the call stack. Where was TypeDecorator->new called from? I'm betting Carp is cleaning out the rest of the stack...any way to keep it?

Thanks for the help guys :) As always it's extremely appreciated. Maybe some day I'll get good enough to start returning some favors :)

Replies are listed 'Best First'.
Re: Moose again...Debugging?
by Anonymous Monk on Dec 18, 2010 at 18:06 UTC
    Note that the module that's being used is MooseX::Types, not "MooseX", which is a namespace containing modules for extending Moose. I believe that only the Moose project itself consumes the "Moose" namespace. This apparently reduces confusion with such an expansive project.

    Here's the relevant portion of MooseX::Types::TypeDecorator, version "0.25", downloaded a few minutes ago off of CPAN, via the source link. I'd added a comment to mark line 89.

    sub new { my $class = shift @_; if(my $arg = shift @_) { if(blessed $arg && $arg->isa('Moose::Meta::TypeConstraint')) { return bless {'__type_constraint'=>$arg}, $class; } elsif( blessed $arg && $arg->isa('MooseX::Types::UndefinedType') ) { ## stub in case we'll need to handle these types different +ly return bless {'__type_constraint'=>$arg}, $class; } elsif(blessed $arg) { __PACKAGE__->_throw_error("Argument must be ->isa('Moose:: +Meta::TypeConstraint') or ->isa('MooseX::Types::UndefinedType'), not +". blessed $arg); } else { __PACKAGE__->_throw_error("Argument cannot be '$arg'"); } # line 89 } else { __PACKAGE__->_throw_error("This method [new] requires a single + argument."); } }

    MooseX::Types says <q>MooseX::Types uses MooseX::Types::TypeDecorator to do some overloading which generally allows you to easily create union types. As with parameterized constrains, this overloading extends to modules using the types you define in a type library.</q> This leads me to believe this could be evoked from all sorts of attribute-defining code.

    It would help to show us line 74 of PI.pm, where _create_pattern_obj is apparently evoking an invocation of this type decorator stuff. I'm not familiar with MooseX::Types at all, so I don't know what using it would look like, though I have played with Moose a little.

      Yeah, I checked out that code as well. Didn't tell me much unfortunately, other than it appears to expect a TypeConstraint object and wasn't finding it which was confirmed by the additional debug output I put in. I'd like to know where it was being called from so I could trace the problem back, but it's not on the call stack.

      Here's the relevent code:

      method _create_pattern_obj (Str :$name, Maybe[Str] :$mask_data, Mayb +e[Str] :$tag_data) { my $tags = {}; map {$tags->{$_} = 1;} split(',', $tag_data) if defined $tag_data; my $pattern_obj = Program::Plist::Pl::Pattern->new(name => $name, mask_data => $m +ask_data, tags => $tags); $self->_add_pattern($pattern_obj); }

      The relevant line throwing the error is the call to Program::Plist::Pl::Pattern->new.

        After many attempts at using MooseX::Declare, I gave up and moved everything to vanilla Moose. I had hoped that after learning the basics the huge errors would make sense or be significantly less frequent but I was unable to reach that point. From my experiences, I personally think that MooseX::Declare (and Method::Signatures) is just over the edge of too magical.

        Good Day,
            Dean

        Oh, you're using MooseX::Declare! Yeah, that'll make debugging like poking a lunar rover.

        My first thought is to run the program with the argument -MO=Deparse and see if the generated code is of any help. I guess you'd have to find where the right ::TypeDecorator object is created and what's going wrong there. This will likely take some time, and there will be a lot of indirection, but it's taking the mystery meat syntax out of the equation.

        I keep thinking about ::Pattern's constructor, and I have to remind myself that Moose is providing that, so it's unlikely that you have a bad method signature that doesn't allow that argument (but usually bad args have more obvious error messages in MooseX::Delare, in my experience). Although, if new is inadvertantly defined, maybe that's part of the problem.