How to use Moose::Util::TypeConstraints for custom types?
Question
How to use Moose::Util::TypeConstraints for custom types?
Using Moose::Util::TypeConstraints to create custom types in Perl's Moose object system is a powerful way to add domain-specific validation to your attributes. It lets you define your own type constraints, enabling you to enforce rules beyond the built-in Moose types like Str, Int, and ArrayRef.
What is Moose::Util::TypeConstraints?
This module provides functions to define, combine, and manipulate type constraints, which are essentially predicates that validate attribute values. Custom types increase readability and robustness by centralizing validation logic.
Key Concepts
- Type Constraint: a test that returns true/false for a value.
- Subtype: a type defined as a subset of an existing type.
- Where clause: the actual predicate that checks each value.
- Message: an optional error message for constraint failures.
Basic Usage
You typically use these functions:
subtype: define a new subtype with a constraint on an existing parent type.coerce: optionally define coercions to convert values into the right type.class_type: define a type based on a Perl class (for objects).enum: define enumerated string sets.
Example: Defining and Using a Custom Type
This example creates a subtype OddInt which accepts only odd integers, demonstrating how to define a subtype, use it in a Moose class attribute, and see the validation in action.
use strict;
use warnings;
use Moose;
use Moose::Util::TypeConstraints;
# Define a subtype of Int that accepts only odd integers
subtype 'OddInt',
as 'Int',
where { $_ % 2 == 1 },
message { "$_ is not an odd integer" };
# Define a simple Moose class with an 'odd_number' attribute constrained by OddInt
{
package MyOddNumberHolder;
use Moose;
has 'odd_number' => (
is => 'rw',
isa => 'OddInt',
required => 1,
);
__PACKAGE__->meta->make_immutable;
}
# Demonstration:
my $obj = MyOddNumberHolder->new(odd_number => 5);
print "Odd number is: ", $obj->odd_number, "\n";
eval {
my $bad_obj = MyOddNumberHolder->new(odd_number => 4);
};
if ($@) {
print "Error caught: $@\n";
}
How it works
- The
subtypedefinesOddInt> as anIntwhere the value modulo 2 is 1. Themessagecustomizes the error shown on validation failure. - The Moose attribute
odd_numberrequires anOddInt, so setting a wrong value triggers an exception. - The
evalblock catches the exception when trying to instantiate with an even number, demonstrating failure.
Common Pitfalls
- Always provide a useful
messagein your subtype for better error diagnostics. - Remember Moose type constraints are checked when attributes are set or objects constructed; lazy attributes might defer this.
- Using coercions with custom types adds convenience but be mindful of unexpected automatic conversions.
- Moose versions before 2.0 may have subtly different behavior in the type constraint API, so check version compatibility.
Summary
By leveraging Moose::Util::TypeConstraints, you can craft precise, reusable validation rules tailored to your domain, keeping your Moose attributes clean and robust. This approach exemplifies Perl's "There’s More Than One Way To Do It" (TMTOWTDI) spirit—multiple ways to validate data, but custom Moose type constraints give you a declarative, idiomatic, and maintainable way to encapsulate validation consistently.
Verified Code
Executed in a sandbox to capture real output. • v5.34.1 • 165ms
Odd number is: 5
Error caught: Attribute (odd_number) does not pass the type constraint because: 4 is not an odd integer at constructor MyOddNumberHolder::new (defined at - line 24) line 39
MyOddNumberHolder::new('MyOddNumberHolder', 'odd_number', 4) called at - line 32
eval {...} at - line 31
(empty)Was this helpful?
Related Questions
- 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?
- How to implement multiple inheritance with Moose in Perl?