How to use coercion with Moo attributes in Perl?
Question
How to use coercion with Moo attributes in Perl?
In Moo, attribute coercion is not built-in like in Moose, but you can implement it with Type::Tiny-based tools such as Type::Utils and Types::Standard. The key is to declare a type constraint and define coercions explicitly, then enable coercion on your attribute.
The previous example failed because Dumper was not correctly imported or called: calling Dumper as a method (e.g. $obj->Dumper) causes an undefined subroutine error. Instead, you must use use Data::Dumper; and call Dumper() as a standalone function.
Working Example: Attribute Coercion with Moo Using Type::Tiny
use strict;
use warnings;
use Moo;
use Types::Standard qw(ArrayRef Str);
use Type::Utils qw(declare as coerce from via);
use Data::Dumper;
# Declare a new type constraint for ArrayRef of Str
my $TagArrayType = declare
as ArrayRef[Str];
# Coerce from Str to ArrayRef[Str]
coerce $TagArrayType,
from Str,
via { [$_] };
# Coerce from ArrayRef (identity)
coerce $TagArrayType,
from ArrayRef,
via { $_ };
{
package MyClass;
use Moo;
use Types::Standard qw(ArrayRef Str);
use Data::Dumper;
has tags => (
is => 'rw',
isa => $TagArrayType,
coerce => 1,
default => sub { [] },
);
sub dump_tags {
my ($self) = @_;
print Dumper($self->tags);
}
}
# Create objects with and without coercion
my $obj1 = MyClass->new(tags => 'single_tag'); # Coerced into ['single_tag']
my $obj2 = MyClass->new(tags => ['tag1', 'tag2']); # Passed as-is
print "Object 1 tags:\n";
$obj1->dump_tags();
print "Object 2 tags:\n";
$obj2->dump_tags();
Explanation
declare as ArrayRef[Str]creates a type constraint object for arrays of strings used for attribute validation.- The
coercefunction adds conversion rules fromStrtoArrayRef[Str], and identity fromArrayRef. - Setting
coerce => 1on thetagsattribute enables automatic conversion from input values according to the coercion rules. Data::Dumper::Dumper()is called as a standalone function, not a method, so it prints out the coerced attribute correctly.- This example works out of the box with core modules plus
MooandType::Tinyecosystem installed.
Common Pitfalls
- Calling
Dumperas a method ($obj->Dumper) triggers errors; useprint Dumper($data)instead. - Without assigning the result of
declare as ...to a variable, coercion won't work. - Only one
from =>source percoercecall is allowed. - This method requires the
Type::Tinyecosystem modules (Type::Utils,Types::Standard) available in your environment.
Summary
Although Moo doesn't automatically support attribute coercion like Moose, you can effectively add it using the Type::Tiny ecosystem. Declare your types, define coercions explicitly, and enable coercion on attributes to accept multiple input forms gracefully. Always remember to call utility functions like Dumper correctly to avoid runtime errors.
Verified Code
Executed in a sandbox to capture real output. • v5.34.1 • 75ms
Object 1 tags:
$VAR1 = [
'single_tag'
];
Object 2 tags:
$VAR1 = [
'tag1',
'tag2'
];
(empty)Was this helpful?
Related Questions
- How to use Moose::Util::TypeConstraints for custom types?
- How to implement method delegation in Perl Moo?
- How to use Type::Tiny with Moo for strict typing in Perl?
- How to use required attributes in Perl Moo and Moose?
- How to convert a Perl Moo class to Moose?
- How to use Moo lazy_build for attribute defaults in Perl?