Skip Menu |

This queue is for tickets about the Moose CPAN distribution.

Report information
The Basics
Id: 52095
Status: rejected
Priority: 0/
Queue: Moose

People
Owner: stevan.little [...] gmail.com
Requestors: perl [...] david-raab.de
Cc:
AdminCc:

Bug Information
Severity: Important
Broken in: 0.93
Fixed in: (no value)



Subject: Native Traits and Coercion
In the attachment you see a simple "Person" class that i build with primary 2 attributes and a self build subtype. The subtype "MyURI" that needs to be a "URI" class with Coercion from a string. When i set it to the "url" attribute then everything works like expected. But when i try to add it with "add_bookmark" then the type failed with the error message. Show quoted text
> Method 'url' returned a URI object > Value http://www.heise.de did not pass container type constraint > 'MyURI' at /home/sidburn/perl510/lib/site_perl/5.10.1/Moose > /Meta/Attribute/Native/MethodProvider/Array.pm line 129 >
Moose::Meta::Attribute::Native::MethodProvider::Array::__ANON__('Person=HASH(0x9b7a8c8)', 'http://www.heise.de') called at /home/sidburn/perl510/lib/site_perl Show quoted text
> /5.10.1/Moose/Meta/Attribute/Native/Trait.pm line 127 > Person::add_bookmark('Person=HASH(0x9b7a8c8)', > 'http://www.heise.de') called at ./coerce.pl line 49
It seems that when i do "add_bookmark" the type "ArrayRef[MyURI]" works that it only accepts the "MyURI" type, but the coercion from Str does not get applied.
Subject: coerce.pl
#!/usr/bin/env perl # Core Modules use strict; use warnings; use utf8; { package Person; use Moose; use Moose::Util::TypeConstraints; use URI; subtype 'MyURI', as 'Object', where { $_->isa('URI') }; coerce 'MyURI', from 'Str', via { URI->new($_) }; has 'url' => ( is => 'rw', isa => 'MyURI', coerce => 1, ); has 'bookmarks' => ( traits => ['Array'], is => 'ro', isa => 'ArrayRef[MyURI]', default => sub { [] }, coerce => 1, handles => { add_bookmark => 'push', }, ); } my $you = Person->new; $you->url('http://www.heise.de'); if ( $you->url->isa('URI') ) { print "Method 'url' returned a URI object\n" } else { print "Method 'url' is not an URI Object\n" } $you->add_bookmark('http://www.heise.de');
This is a tricky one actually. Let me first say that we do not and will never (in the core) support what I call "deep-coercions". This means that your MyURI type coercion will never get applied to an attribute with a ArrayRef[MyURI] type. It is just too much "action at a distance" with the potential for subtly hidden bugs and very hard to follow issues. A lot of this has to do with the fact that types are global in Moose and therefore so are coercions. It could be argued that the delegated Native trait methods should handle coercions like you are asking for, but personally I think this still has the same issues as the deep coercions i mention above and even adds some more. For instance, what if I don't want all the delegated methods to coerce? Exactly what coercions do I want applied? (remember types are global so there can be a coercion defined somewhere you don't know about) So the simple (coerce => 1) is not sufficient notation to handle the complexity of these options, which means a new feature and we have a policy on those (see Moose::Manual::Contributing) where new features need to be vetted through MooseX:: modules first (as the native traits feature was via MooseX::AttributeHelpers). So in the end I have to reject this bug and suggest you either write up a MooseX:: to experiment with this feature (come join us on IRC or the mailing list and we will be happy to help guide you through the various Moose guts you will need to extend and override), or you can use the 'around' method modifier to install your own coercion facility, which would look something like this: around 'add_bookmark' => sub { my $next = shift; my $self = shift; my $type = find_type_constraint('MyURI'); $self->$next( $type->coerce(shift) ); }; And remember that the 'around' method modifier can take multiple method names too, so you can do: around 'add_bookmark', 'insert_bookmark', 'consume_bookmark' => sub { my $next = shift; my $self = shift; my $type = find_type_constraint('MyURI'); $self->$next( $type->coerce(shift) ); }; to stack up a set of methods to apply the coercions for. - Stevan On Thu Nov 26 11:32:03 2009, SidBurn wrote: Show quoted text
> In the attachment you see a simple "Person" class that i build with > primary 2 attributes and a self build subtype. The subtype "MyURI" > that > needs to be a "URI" class with Coercion from a string. > > When i set it to the "url" attribute then everything works like > expected. > > But when i try to add it with "add_bookmark" then the type failed with > the error message. >
> > Method 'url' returned a URI object > > Value http://www.heise.de did not pass container type constraint > > 'MyURI' at /home/sidburn/perl510/lib/site_perl/5.10.1/Moose > > /Meta/Attribute/Native/MethodProvider/Array.pm line 129 > >
> Moose::Meta::Attribute::Native::MethodProvider::Array::__ANON__('Person=HASH(0x9b7a8c8)', > 'http://www.heise.de') called at /home/sidburn/perl510/lib/site_perl
> > /5.10.1/Moose/Meta/Attribute/Native/Trait.pm line 127 > > Person::add_bookmark('Person=HASH(0x9b7a8c8)', > > 'http://www.heise.de') called at ./coerce.pl line 49
> > It seems that when i do "add_bookmark" the type "ArrayRef[MyURI]" > works > that it only accepts the "MyURI" type, but the coercion from Str does > not get applied.
From: perl [...] david-raab.de
Hi, thanks for the fast and good Reply. At the moment i implemented it in my application like you posted it with the around modifier. But i think it is good when this statement gets added to the documentation that deep-coercion is not supported and when you need it how you can solve it (probably adding a new reciepe?). From Christmas to New Year i have Holidays. Maybe i have time to look how to write a MooseX::* module to archive deep-coercion.
From: david.tulloh [...] AirservicesAustralia.com
On Thu Nov 26 12:07:55 2009, STEVAN wrote: Show quoted text
> This is a tricky one actually. > > Let me first say that we do not and will never (in the core) support > what I call "deep-coercions". This means that your MyURI type coercion > will > never get applied to an attribute with a ArrayRef[MyURI] type. It is > just too much "action at a distance" with the potential for subtly > hidden > bugs and very hard to follow issues. A lot of this has to do with the > fact that types are global in Moose and therefore so are coercions.
I understand the concerns about deep-coercions. Would you consider implementing a straightforward conversion on an array subtype (ArrayRefOfMyURI using the prior example)? The push function actually takes an array, it seems (to me) to be a relatively safe move to convert the array to an array ref. So the coercion could be against the full ArrayRefOfMyURI array. In the most common single element use it would simply be a one element array. This could be applied for the push and shift functions. Unfortunately it leaves the insert and set functions with the original problem. I'm not sure if you view half support as better than none.
Sorry, no I would not consider that, for exactly the reason you state at the end, that this is a half solution and leaves the insert and set functions to not work. Deep Coercions are simply too much "action at a distance"/DWIMery to put in core. This doesn't mean they are not useful, they are just too powerful to be "always on". - Stevan On Thu Feb 18 22:03:37 2010, david.tulloh@AirservicesAustralia.com wrote: Show quoted text
> On Thu Nov 26 12:07:55 2009, STEVAN wrote:
> > This is a tricky one actually. > > > > Let me first say that we do not and will never (in the core) support > > what I call "deep-coercions". This means that your MyURI type coercion > > will > > never get applied to an attribute with a ArrayRef[MyURI] type. It is > > just too much "action at a distance" with the potential for subtly > > hidden > > bugs and very hard to follow issues. A lot of this has to do with the > > fact that types are global in Moose and therefore so are coercions.
> > I understand the concerns about deep-coercions. > > Would you consider implementing a straightforward conversion on an array > subtype (ArrayRefOfMyURI using the prior example)? > > The push function actually takes an array, it seems (to me) to be a > relatively safe move to convert the array to an array ref. So the > coercion could be against the full ArrayRefOfMyURI array. In the most > common single element use it would simply be a one element array. > > This could be applied for the push and shift functions. Unfortunately > it leaves the insert and set functions with the original problem. I'm > not sure if you view half support as better than none.