Hey, based on your dumps, I'm not sure you are on the latest MX:Types and all. Could you check that so that I can start to look through this and see if there are any bugs I can create a test case out of? Thanks!
john ----- Original Message ---- From: Stevan Little <stevan.lit...@iinteractive.com> To: i...@sillit.com Cc: moose@perl.org Sent: Thursday, January 29, 2009 1:13:03 PM Subject: Re: MooseX::Types : subtype/coerce not found in Roles (hand_optimized_type_constraint?) 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, i...@sillit.com 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 <stevan.lit...@iinteractive.com> 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