user2103008
user2103008

Reputation: 524

using aliased with Moose doesn't seem to work when declaring classes

I'm a bit new to Perl. I'm trying to define/use a class in the following manner:

package A::B::C;
use strict;
use warnings;
use Moose;
use aliased 'A::B::D';
has 'attribute' => (isa => 'ArrayRef[D]', is => 'ro', required => 1);

While creating an object:

use aliased 'A::B::C';
use aliased 'A::B::D';
my $aref = [D->new()];
C->new($aref);

However this fails as Moose complains:

Attribute (attribute) does not pass the type constraint because: Validation failed for 'ArrayRef[D]' with value ARRAY(0x7f2b658b51c0)

But, if I switch to not using aliases, it works(as it of course should):

package A::B::C;
use strict;
use warnings;
use Moose;
use A::B::D;
has 'attribute' => (isa => 'ArrayRef[A::B::D]', is => 'ro', required => 1);

My question is why does the use aliased bit not work with Moose?

Thanks

Upvotes: 1

Views: 53

Answers (1)

Jonathan Cast
Jonathan Cast

Reputation: 4635

Moose doesn't know about use aliased. The pragma use aliased is a hack on top of Perl; all it does is create a subroutine with a short name that returns the class name. So

use aliased 'A::B::D';

is equivalent to

use A::B::D;

sub D() { 'A::B::D' }

(see aliased.pm#L45)

Then, when you say something like D->new(), Perl notices that there is a subroutine (constant) named D and interprets D as a subroutine call, then does the method call on the result. (Rather than interpreting D as a string constant like it normally would). Even to Perl, D is not really a package name; just something that acts like a package name!

Furthermore, Moose has its own system for parsing type declarations (which is why you can give them as a string like you did) and its own global notion of type declarations. None of that knows about aliased, so Moose is using its default behavior of treating un-recognized types as (global) package names.

If you understand how aliased works, you could take advantage of it by doing

has 'attribute' => (isa => 'ArrayRef['.D.']', is => 'ro', required => 1);

but it's probably better to remember that

Type names are global throughout the current Perl interpreter

and either use fully-qualified package names as types everywhere, or use Type::Tiny and write

package A::B::C;

use Moose;

use aliased 'A::B::D';

use Types::Standard qw/ ArrayRef /;
use Type::Utils qw( class_type );

has 'attribute' => (isa => ArrayRef[class_type D], is => 'ro', required => 1);

(note the lack of quotes around D, possible only because of the use aliased!).

(Type::Tiny will probably be faster than Moose types, so you might want to consider it anyway).

Upvotes: 1

Related Questions