How to define a class with attributes using Moo in Perl?
Question
How to define a class with attributes using Moo in Perl?
When defining a class with attributes using Moo in Perl, it's important to remember that has—the keyword for declaring attributes—is exported into the package where you call use Moo;. If you define your class inside a block or another scope without proper package declaration and loading Moo inside that package, Perl won't recognize has. This leads to errors like "Do you need to predeclare has?".
To fix this, you must place use Moo; directly inside the package declaration where you want to define attributes. Also, be careful to avoid variable redeclaration warnings by not redeclaring my $p multiple times. The cleanest approach is to define the package with use Moo; inside it, then use your class outside.
Corrected Working Example Using Moo
use strict;
use warnings;
use feature 'say';
{
# Define a package for the class
package Person;
# Import Moo inside the package to get 'has'
use Moo;
# Read-only attribute 'name' (required)
has 'name' => (
is => 'ro',
required => 1,
);
# Read-write attribute 'age' with default 0
has 'age' => (
is => 'rw',
default => sub { 0 },
);
# Method to describe the person
sub describe {
my $self = shift;
return $self->name . " is " . $self->age . " years old.";
}
}
# Usage outside the package block
my $person = Person->new(name => 'Alice', age => 30);
say "Name: ", $person->name;
say "Age: ", $person->age;
say $person->describe();
$person->age(31);
say "New age: ", $person->age;
Explanation
use Moo;must be inside thepackage Person;block to correctly export thehaskeyword to that package’s namespace.hasdefines attributes:is=>'ro'means read-only, andis=>'rw'allows reading and writing.- The
required => 1option forces the attribute to be passed to the constructor. - Default values use coderefs (like
sub { 0 }) to avoid shared references across objects. - Attributes act as accessor methods: calling
$person->agegets the value;$person->age(31)sets a new value.
Common Gotchas
- Always put
use Moo;inside your package that will have attributes. - Avoid defining classes inside bare blocks without a proper package statement and
use Moo;there. - Do not redeclare variables with
myrepeatedly in the same scope to avoid masking warnings. - Use Perl 5.8+ for
Moo, but 5.10+ is recommended for features likesay.
By following this pattern, you can define clean, lightweight classes with Moo that provide flexible attribute handling without heavy dependencies.
Verified Code
Executed in a sandbox to capture real output. • v5.34.1 • 38ms
Name: Alice
Age: 30
Alice is 30 years old.
New age: 31
(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?