Re: MooseX::Types : subtype/coerce not found in Roles (hand_optimized_type_constraint?)
[email protected] (Stevan Little)
| Newsgroups | perl.moose |
|---|---|
| Message-ID | <[email protected]> |
Ian, If your looking to decrease fragility in a framework, but don't want to have to enforce some kind of "you must load this 3 modules in this order" rule, then you might want to look into the docs on extending and embedding Moose. Then you do can just do: package My::App; use My::Framework; # load Moose and all your deps in strict order - Stevan On Jan 30, 2009, at 3:37 AM, Ian Sillitoe wrote: > Stevan, > > Thanks to your comments I managed to fix my code - it was driving me > nuts so I really appreciate your help. I now need to go back through > my changes to find out exactly which bit fixed the problem so I > understand it better. > > The process of untangling module dependencies in my local code base > wasn't terribly pleasant even though I don't _think_ I'm doing > anything too unusual or circuitous. So while I'm obviously happy > that my tests now pass, I'm worried that things are left a little > fragile (although I'm aware the perceived fragility is most likely > caused by my lack of understanding, which I'm working on). > > One of my goals at $work was to write an internal framework that > would be easy for others to use, understand and extend - I'm now > concerned that I'm leaving a fairly large and unpleasant gotcha > lurking under the surface. Happy for hear any more ideas about > techniques to help avoid this in the future. > > Cheers, > > Ian > > > > > > 2009/1/29 Stevan Little <[email protected]> > I tend to do the following: > > - make a MyApp::Types package that handles *all* custom type > definitions and type coercions > - make all other packages load MyApp::Types (even if they dont need > it, because their deps might need it) > > Then as far as circular refs are concerned, they are tricky and each > case is a little different. The key is to map out what you need and > the force things to load in that order (this is where the global > MyApp::Types can be really handy). > > Also, find_type_constraint is your friend, it is exported from > Moose::Util::TypeConstraints and can basically be used to detect if > the type already exists or not. Something like: > > if (find_type_constraint('Foo')) { > # do something wiht the Foo type here, like add a coercion > } > > Of course the ideal situation is that you break your circular refs > instead, but sometimes that is just not possible. > > - Stevan > > > On Jan 29, 2009, at 11:59 AM, [email protected] wrote: > > Stevan, > > Many thanks for getting back so quickly - that sounds exactly the sort > of thing that must be happening. > > Before I dive in - could I ask what the recommended best practice for > avoiding circular "use" cases is (if any)? I've generally tried to > "use" all the modules required by the package to keep each package as > independent as possible without loading everything unneccessarily. Or > am I missing something? > > Cheers > > Ian > > On 29/01/2009, Stevan Little <[email protected]> wrote: > Ian, > > Types can sometimes be very sensitive to load order since they are > really done at runtime (it is the runtime immediately following > compile time, but still runtime). Based on your description I think > you are getting bitten by the auto-creation of types (if Moose doesn't > know the type it makes it into a Object subtype that isa(<name of > type>)). > > I would check to make sure that you do not have any circular > dependencies in how you load your modules, Perl will handle these > fine, but Moose types will be sensitive to the order in which the > circle is traversed. > > - Stevan > > On Jan 29, 2009, at 6:54 AM, Ian Sillitoe wrote: > > Hello, > > I have a problem with subtype/coercions (MooseX::Types library) that > I've > spent ages trying to understand, then ages trying abstract into a > simple > test case but all simple cases seem to work as expected but just not > in my > larger code base. I was hoping that if I put the symptoms up someone > may > spot what is going on and put me out of my misery (or at least point > me to > where I should continue my digging). > > Please excuse any typos in the (incomplete) example code below. I > have coded > up a full version of this simple scenario and I can't replicate the > error > I'm getting in my real code base anyway - so this is meant purely for > illustration. > > # Types library > package My::Types; > use Moose; > use MooseX::Types -declare [qw( Version DomainID )]; > use My::Version; > > subtype 'Version', > as 'Object', > where { $_->isa( 'My::Version' ) }; > > coerce 'Version', > from 'Str', > via { My::Version::init_from_string( $_ ) }; > > subtype 'ObjectID', > as 'Str'; > > # Role to associate versions with objects > package My::Role::Verisoned; > use Moose::Role; > use My::Types qw(Version); > has 'version' => (is => 'rw', isa => 'Version', coerce => 1); > > # Versioned Object1 > package My::Object1; > use Moose; > with 'My::Role::Versioned'; > > # Versioned Object2 > package My::Object2; > use Moose; > use My::Types qw( DomainID ); > use My::Object1; > with 'My::Role::Versioned'; > > has 'domain_id' => ( is => 'rw', isa => 'DomainID' ); > > sub get_object1 { > my $self = shift; > return My::Object1->new( version => $self->version ); > } > > In this simple case, the subtype/coerce works as expected in both > objects > (the type constaint of the 'version' attribute is the identical) > > $o2 = My::Object2->new( version => '3.2' ); > $o1 = $o2->get_object1; > > warn "Object1: " . > My::Object1->meta->get_attribute_map->{version}->{type_constraint}- > dump; > warn "Object2: " . > My::Object2->meta->get_attribute_map->{version}->{type_constraint}- > dump; > > Object1: $VAR1 = bless( { > 'compiled_type_constraint' => 'CODE(0xa41e310)', > 'parent' => 'My::Version', > 'coercion' => > 'Moose::Meta::TypeCoercion=HASH(0xa991c70)', > 'name' => 'Version', > 'constraint' => 'CODE(0x9eb4600)', > 'package_defined_in' => 'My::Types' > }, 'Moose::Meta::TypeConstraint' ); > > Object2: $VAR1 = bless( { > 'compiled_type_constraint' => 'CODE(0xa41e310)', > 'parent' => 'My::Version', > 'coercion' => > 'Moose::Meta::TypeCoercion=HASH(0xa991c70)', > 'name' => 'Version', > 'constraint' => 'CODE(0x9eb4600)', > 'package_defined_in' => 'My::Types' > }, 'Moose::Meta::TypeConstraint' ); > > However, in what seems to be a similar scenario in my live code, I > get the > error that the 'version' attribute doesn't pass the type constraint > when > creating an instance of Object1 inside Object2::get_object1 (it no > longer > seems to be aware of the subtype/coercion in My::Types): > > Attribute (version) does not pass the type constraint because: > Validation > failed for 'Version' failed with value > My::Version::V3_2_0=HASH(0x1aea0930) > at .../Moose/Meta/Attribute.pm line 415 > > When I look at the type constraint of the 'version' attribute in > these two > classes they now appear different: > > warn "Object1: " . > My::Object1->meta->get_attribute_map->{version}->{type_constraint}- > dump; > warn "Object2: " . > My::Object2->meta->get_attribute_map->{version}->{type_constraint}- > dump; > > Object1: $VAR1 = bless( { > 'compiled_type_constraint' => 'CODE(0x1ae87c00)', > 'parent' => 'Object', > 'hand_optimized_type_constraint' => > $VAR1->{'compiled_type_constraint'}, > 'name' => 'Version', > 'constraint' => 'CODE(0x1a3c4b80)', > 'class' => 'Version' > }, 'Moose::Meta::TypeConstraint::Class' ); > > Object2: $VAR1 = bless( { > 'compiled_type_constraint' => 'CODE(0x1a929c10)', > 'parent' => 'My::Version', > 'coercion' => > 'Moose::Meta::TypeCoercion=HASH(0x1ae9da00)', > 'name' => 'Version', > 'constraint' => 'CODE(0x1a3c4b80)', > 'package_defined_in' => 'My::Types' > }, 'Moose::Meta::TypeConstraint' ); > > > I hope that difference shows what I might be doing wrong or where to > start > looking (parent => 'Object'? hand_optimized_type_constraint?). This > change > appears to be related to which modules have been "use"d -- in my > live code I > can remove this error by *taking out* the equivalent of "use > My::Types" on > Object2. > > Very much appreciate any help/pointers. > > Cheers, > > Ian > > > -- > Ian Sillitoe > CATH Team -- http://cathdb.info > > > > > -- > Ian Sillitoe > CATH Team -- http://cathdb.info > > > > > -- > Ian Sillitoe > CATH Team -- http://cathdb.info >