Re: MooseX::Types : subtype/coerce not found in Roles (hand_optimized_type_constraint?)

[email protected] (Ian Sillitoe)
Newsgroups perl.moose
Message-ID <[email protected]>
Thanks Stevan. As it happens I'm already using the My::Framework approach -
the bit that I was getting stuck on (which now seems fairly obvious) was
that I was "use"ng packages in the My::Types library (required for some of
the coercions).

e.g. to support the "My::Versioned" role being initialised from a string I
had something like:

*  package My::Object;
*  use Moose;
  with 'My::Versioned';

*  package My::Versioned;
*  use My::Types qw( Version );
  use Moose::Role;
  has 'version' => (is => 'rw', isa => 'Version');

*  package My::Types
*  use MooseX::Types -declare ['Version'];
> use My::Version;

  subtype 'Version'
      => as 'Object'
      => where { $_->isa( 'My::Version' ) }
      => message { "object '$_' does not appear to be a valid Version" };

  coerce 'Version'
      => from 'Str'
          => via { My::Version::init_from_string( $_ ) };

I localised the "use" statements in the My::Types package to take them out
of the compile-time loop:

- use My::Version;

  coerce 'Version'
      => from 'Str'
-         => via { My::Version::init_from_string( $_ ) };
+         => via { use My::Version; My::Version::init_from_string( $_ ) };

Is this a really horrible hack?



2009/1/30 Stevan Little <[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
>>
>>
>


-- 
Ian Sillitoe
CATH Team -- http://cathdb.info
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.