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,Moois lightweight but supports this attribute style seamlessly. - For complex default values or lazy building of read-only attributes, you can use
default => sub { ... }orbuilder => '_build_foo'. - Remember that Perl’s sigils (+ the
isoption) determine method generation:romeans read-only,rwread/write, andlazyfor lazy initialization. - Because
roattributes 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
Person's name: Alice
Error on trying to modify read-only attribute: Usage: Person::name(self) at - line 25.
(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?