I have written a set of classes and interfaces that are implemented in Moose also using roles. What I am having trouble understanding is the exact differences in both usage and implementation of Moose traits vs. roles.
The Moose documentation states:
It is important to understand that roles and traits are the same thing. A role can be used as a trait, and a trait is a role. The only thing that distinguishes the two is that a trait is packaged in a way that lets Moose resolve a short name to a class name. In other words, with a trait, the caller can refer to it by a short name like "Big", and Moose will resolve it to a class like MooseX::Embiggen::Meta::Attribute::Role::Big.
It is my understanding that traits and roles are "the same". However, when implementing a basic test of the idea using the use Moose -traits 'Foo'
syntax does not seem to do what I would expect. Surely I must be missing something here.
This first example fails with "Can't locate object method 'foo'"
package MyApp::Meta::Class::Trait::HasTable;
use Moose::Role;
sub foo { warn 'foo' }
package Moose::Meta::Class::Custom::Trait::HasTable;
sub register_implementation { 'MyApp::Meta::Class::Trait::HasTable' }
package MyApp::User;
use Moose -traits => 'HasTable';
__PACKAGE__->foo(); #Can't locate object method 'foo'
Compared to this one (which does work):
package MyApp::Meta::Class::Trait::HasTable;
use Moose::Role;
sub foo { warn 'foo' }
package Moose::Meta::Class::Custom::Trait::HasTable;
sub register_implementation { 'MyApp::Meta::Class::Trait::HasTable' }
package MyApp::User;
use Moose;
with 'MyApp::Meta::Class::Trait::HasTable';
__PACKAGE__->foo(); #foo
This is the only difference in how Moose uses the terms "Trait" and "Role".
Moose's documentation and APIs often use the term "traits" as "Roles applied
to Metaclasses". In your revised answer your first example applies the Role to
MyApp::User
's metaclass via -traits
, the second example applies it to the
class.
If you change your first example to:
package MyApp::Meta::Class::Trait::HasTable;
use Moose::Role;
sub foo { warn 'foo' }
package Moose::Meta::Class::Custom::Trait::HasTable;
sub register_implementation { 'MyApp::Meta::Class::Trait::HasTable' }
package MyApp::User;
use Moose -traits => 'HasTable';
__PACKAGE__->meta->foo();
You'll see "foo at [script]. line 3.
" Which is exactly what it supposed to
be doing.
UPDATE: Apparently I'm not exactly correct here. Traits are roles applied to instances. The -traits
hook applies HasTable to the metaclass instance for MyApp::User. I have updated the relevant Moose docs.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With