http://www.perlmonks.org?node_id=872597

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

I've just been picking up and messing with Moose and I've been left with a few questions about it.

First off, in the Moose::Util::TypeConstraints documentation on cpan, the author mentions this:

It is always a good idea to quote your type names.

This prevents Perl from trying to execute the call as an indirect object call. This can be an issue when you have a subtype with the same name as a valid class.

For instance:

subtype DateTime => as Object => where { $_->isa('DateTime') };

will just work, while this:

use DateTime; subtype DateTime => as Object => where { $_->isa('DateTime') };

will fail silently and cause many headaches. The simple way to solve this, as well as future proof your subtypes from classes which have yet to have been created, is to quote the type name:

use DateTime; subtype 'DateTime' => as 'Object' => where { $_->isa('DateTime') };

However, he seems to be just about the only one that does quote his type names. His reasoning seems sound though, so I figured I'd stick with it.

Unfortunately, it seems to be hit and miss. I have the following code:

use strict; use warnings; package Foo; use Moose; use TmpTypes qw(NewType); has 'item' => (isa => NewType, is => 'rw', required => 1, coerce => 1); sub is_new { my ($self, $item) = @_; return "Yup, ($item) is new!\n" if (is_NewType($item)); return "Nope, ($item) is old.\n"; } package main; use TmpTypes qw(NewType); my $obj = Foo->new(item => 'car'); my $thing = $obj->item; print "Is $thing new? ".$obj->is_new($thing); $thing = 'house'; print "Is $thing new? ".$obj->is_new($thing); $thing = to_NewType('House'); print "Is $thing new? ".$obj->is_new($thing);

And:

package TmpTypes; use strict; use warnings; use MooseX::Types -declare => [qw(NewType)]; use MooseX::Types::Moose qw(Str); subtype NewType, as Str, where {$_ =~ /^new_/}; coerce NewType, from Str, via { 'new_'.$_ };

This works as expected. Now I add quotes to all my type names. Here in the main file:

has 'item' => (isa => 'NewType',

And here in the TmpTypes package:

subtype 'NewType', as 'Str', where {$_ =~ /^new_/}; coerce 'NewType', from 'Str', via { 'new_'.$_ };
With this new code, I get:
WARNING: String found where Type expected (did you use a => instead of a , ?) at TmpTypes.pm line 12
WARNING: String found where Type expected (did you use a => instead of a , ?) at TmpTypes.pm line 12
WARNING: String found where Type expected (did you use a => instead of a , ?) at TmpTypes.pm line 16
WARNING: String found where Type expected (did you use a => instead of a , ?) at TmpTypes.pm line 16
You cannot coerce an attribute (item) unless its type (TmpTypes::NewType) has a coercion at tmp8.pl line 10
Attribute (item) does not pass the type constraint because: Validation failed for 'TmpTypes::NewType' with value car (not isa TmpTypes::NewType) at /nfs/pdx/disks/nehalem.pde.077/perl/lib64/site_perl/x86_64-linux/Moose/Meta/Attribute.pm line 883
However, if I add this to the main package:

use Moose::Util::TypeConstraints; These warnings and errors go away and I'm left with:

MooseX::Types::__ANON__(): Unable to find type 'NewType' in library 'TmpTypes' at tmp8.pl line 19
So first question, Why is this module necessary to quote your type names?

I traced the new error message, and find out that it stems from this line in the Foo class and is due to the is_NewType function: return "Yup, ($item) is new!\n" if (is_NewType($item)); Once I remove that line, the code again works until encountering the to_NewType function in the main package (which it says is an undefined subroutine &main::to_NewType). It looks like while everything else works with the quoted type name, the to_$type and is_$type functions aren't properly exported? So onto my last questions:

Is the problem just an error in the code that is causing this failure (this stuff's pretty new to me)? For completeness, here's the final code:

use strict; use warnings; use Moose::Util::TypeConstraints; package Foo; use Moose; use TmpTypes qw(NewType); has 'item' => (isa => 'NewType', is => 'rw', required => 1, coerce => 1); sub is_new { my ($self, $item) = @_; return "Yup, ($item) is new!\n" if (is_NewType($item)); return "Nope, ($item) is old.\n"; } package main; use TmpTypes qw(NewType); my $obj = Foo->new(item => 'car'); my $thing = $obj->item; print "Is $thing new? ".$obj->is_new($thing); $thing = 'house'; print "Is $thing new? ".$obj->is_new($thing); $thing = to_NewType('House'); print "Is $thing new? ".$obj->is_new($thing);
And:
package TmpTypes; use strict; use warnings; use MooseX::Types -declare => [qw(NewType)]; use MooseX::Types::Moose qw(Str); subtype 'NewType', as 'Str', where {$_ =~ /^new_/}; coerce 'NewType', from 'Str', via { 'new_'.$_ };
So the big question. Should you try to quote your type names? Is the original concern valid? If it is, why do so few module authors do so? Granted I could see the problem coming up only rarely, but I could also see the issue being a real pain to debug. And if you should quote the type names, how do you get the above code to work properly?

Replies are listed 'Best First'.
Re: Some Moose questions
by stvn (Monsignor) on Nov 19, 2010 at 22:26 UTC

    You are confusing core Moose types with MooseX::Types.

    Core Moose types (those created with Moose::Util::TypeConstratints are not the same as MooseX::Types created types. If you are not using MooseX::Types, then you will always want to quote your type names because of exactly the documented issue you quoted. However with MooseX::Types, a subroutine is created for you which you can then use as a bareword so quoting is not needed (however you do need to watch out for automagic stringification using the fat comma).

    -stvn
      Oooh so let's make certain I understand this then. That means the MooseX::Types::Moose is giving you the core Moose types as MooseX::Types types which then means you don't have to worry about quoting those either, right?

        Yes, exactly.

        -stvn
      Excellent, that makes me feel better about not using quotes then. I had planned to use MooseX::Types. There's just so much Moose documentation that I was getting confused while I waded through it all. I appreciate you taking the time out to help!