oop beginner

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 the package Person; block to correctly export the has keyword to that package’s namespace.
  • has defines attributes: is=>'ro' means read-only, and is=>'rw' allows reading and writing.
  • The required => 1 option 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->age gets 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 my repeatedly in the same scope to avoid masking warnings.
  • Use Perl 5.8+ for Moo, but 5.10+ is recommended for features like say.

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

Tip: edit code and use “Run (Browser)”. Server runs always execute the published, verified snippet.
STDOUT
Name: Alice
Age: 30
Alice is 30 years old.
New age: 31
STDERR
(empty)

Was this helpful?

Related Questions