oop beginner

How to create a read-only attribute in Perl Moo?

Question

How to create a read-only attribute in Perl Moo?

Creating a Read-Only Attribute in Perl Moo

In Perl’s Moo object system, attributes by default generate both a reader method and a writer (setter) method if you specify is => 'rw'. To make an attribute read-only, you simply specify is => 'ro' when declaring the attribute. This creates an accessor method that allows only reading (getting) the attribute’s value, but no setter method to modify it after construction.

This approach aligns with Perl’s philosophy of “There’s More Than One Way To Do It” (TMTOWTDI), giving you an easy, explicit way to make attributes immutable from outside the class.

Key points about read-only attributes in Moo

  • is => 'ro' means only a getter method is created.
  • The attribute value must be set at construction (via new()) or with a default builder.
  • Attempting to call a setter on such attributes will result in a runtime error.
  • You can still mutate internal attributes via internal methods if you want to—but the public interface won’t allow setting.

Simple runnable example

use strict;
use warnings;
use Moo;

# Define a class with a read-only attribute 'name'
package Person {
    use Moo;

    # 'name' is read-only
    has name => (
        is       => 'ro',
        required => 1,  # must provide at construction
    );
}

package main;

# Create a new Person object
my $person = Person->new(name => 'Alice');

# Reading the attribute works fine
print "Person's name: ", $person->name, "\n";

# Attempting to set the attribute after construction will fail
eval { $person->name('Bob') };
if ($@) {
    print "Error on trying to modify read-only attribute: $@\n";
}

Explanation

In this example, the Person class has a single attribute name which is declared with is => 'ro'. This means Moo creates a getter method name() but no setter method. When the object is created, you must provide a value for name (because of required => 1). Trying to change the name later using $person->name('Bob') results in an error because that setter method does not exist.

This pattern is common when you want objects whose attributes should not change once set, making your code safer and easier to reason about.

Additional notes and gotchas

  • Unlike Moose, Moo is lightweight but supports this attribute style seamlessly.
  • For complex default values or lazy building of read-only attributes, you can use default => sub { ... } or builder => '_build_foo'.
  • Remember that Perl’s sigils (+ the is option) determine method generation: ro means read-only, rw read/write, and lazy for lazy initialization.
  • Because ro attributes lack setters, you cannot change their values post-construction, which enforces immutability at the object API level.

Verified Code

Executed in a sandbox to capture real output. • v5.34.1 • 28ms

Tip: edit code and use “Run (Browser)”. Server runs always execute the published, verified snippet.
STDOUT
Person's name: Alice
Error on trying to modify read-only attribute: Usage: Person::name(self) at - line 25.

STDERR
(empty)

Was this helpful?

Related Questions