Perl class feature
last modified November 7, 2026
For most of its history, Perl had no syntax for classes. An object was a
reference blessed into a package, a constructor was a subroutine that built a
hash and called bless, and every accessor was written by hand or
generated by a module such as Moose or Moo. Perl 5.38 introduced a new object
system in the core, based on the Corinna design. It adds the keywords
class, field, and method, generates the
constructor, and stores the object's data in fields that are invisible outside
the class.
The feature is still experimental, so a program enables it with
use experimental 'class', which turns on the feature and silences
the experimental warnings. It has grown with each release: Perl 5.40 added the
:reader attribute and the __CLASS__ keyword, Perl 5.42
added :writer and lexical methods. The examples use
use v5.40 and use v5.42 for the newer attributes;
they were run with Perl 5.44 on Linux. The traditional bless-based
approach is covered in the Perl OOP article.
A first class
A class is declared with the class keyword, its data with
field, and its behaviour with method.
#!/usr/bin/perl
use v5.40;
use experimental 'class';
class Person {
field $name :param;
field $occupation :param;
method info {
return "$name is a $occupation";
}
}
my $p = Person->new(name => 'Jana', occupation => 'gardener');
say $p->info;
say ref $p;
The Person class has two fields. The :param attribute
makes each of them a constructor parameter with the same name. We do not write a
new subroutine; Perl generates it and it accepts named arguments.
Inside a method, the fields are ordinary lexical variables and the object is
available as $self, which is declared automatically. The
ref function returns the class name, just as for a blessed
reference.
$ perl first.pl Jana is a gardener Person
The same class with bless
For comparison, here is the equivalent class written in the classic style, using a signature-based constructor.
#!/usr/bin/perl
package Person;
use v5.40;
sub new($class, %args) {
my $self = {
name => $args{name},
occupation => $args{occupation},
};
return bless $self, $class;
}
sub info($self) {
return "$self->{name} is a $self->{occupation}";
}
package main;
my $p = Person->new(name => 'Jana', occupation => 'gardener');
say $p->info;
$p->{ocupation} = 'teacher';
say $p->info;
The constructor has to collect the arguments, build the hash, and bless it.
The object is a plain hash, so any code can read and write its keys. The last
lines show a classic bug: the misspelt key ocupation silently
creates a new entry, and the program prints the old value without any warning.
With the class feature, a misspelt field name is a compile-time
error, because fields are lexical variables checked by strict.
$ perl bless.pl Jana is a gardener Jana is a gardener
Fields
A field can be a scalar, an array, or a hash. It can have an initializer expression, which is evaluated for each new object and may refer to fields declared before it.
#!/usr/bin/perl
use v5.40;
use experimental 'class';
class Order {
field $id :param;
field @items;
field %qty;
field $label = "order-$id";
method add($item, $count = 1) {
push @items, $item unless exists $qty{$item};
$qty{$item} += $count;
return $self;
}
method summary {
my $lines = join ', ', map { "$_ x$qty{$_}" } @items;
return "$label: $lines";
}
}
my $o = Order->new(id => 17);
$o->add('apple', 3)->add('bread')->add('apple');
say $o->summary;
say builtin::reftype($o);
eval { my $x = $o->{id} };
print "error: $@";
The @items array keeps the order in which items were added and the
%qty hash their quantities; both start empty for every object. The
$label field is computed from $id, which is declared
earlier. The add method returns $self, so calls can be
chained. The object's underlying type, reported by reftype, is the
new OBJECT type; it is not a hash, so trying to reach inside it
with $o->{id} fails. The only way to the data is through the
methods.
$ perl fields.pl order-17: apple x4, bread x1 OBJECT error: Not a HASH reference at fields.pl line 31.
Constructor parameters
The :param attribute connects a field to a constructor argument. A
parameter without a default is mandatory; one with a default is optional.
#!/usr/bin/perl
use v5.40;
use experimental 'class';
class Server {
field $host :param;
field $port :param = 80;
field $timeout :param //= 30;
field $retries :param ||= 3;
field $secure :param(tls) = 0;
method show {
say "$host:$port timeout=$timeout retries=$retries tls=$secure";
}
}
Server->new(host => 'example.com')->show;
Server->new(host => 'example.com', port => 443, tls => 1)->show;
Server->new(host => 'example.com', timeout => undef, retries => 0)->show;
for my $args ([port => 8080], [host => 'a.com', prot => 8080]) {
eval { Server->new(@$args) };
print "error: $@";
}
A default given with = is used when the argument is missing. The
//= default also applies when the argument is undef,
and ||= when it is false, so timeout => undef and
retries => 0 both fall back to the defaults. The form
:param(tls) gives the parameter a different name than the field.
The generated constructor checks its arguments: it dies when a mandatory
parameter is missing and, unlike most hand-written constructors, also when it
receives an unknown one, which catches typos such as prot.
$ perl params.pl example.com:80 timeout=30 retries=3 tls=0 example.com:443 timeout=30 retries=3 tls=1 example.com:80 timeout=30 retries=3 tls=0 error: Required parameter 'host' is missing for "Server" constructor at params.pl line 23. error: Unrecognized parameters for "Server" constructor: prot at params.pl line 23.
Readers and writers
The :reader attribute generates a method that returns the field's
value. Perl 5.42 added :writer, which generates a method that sets
it.
#!/usr/bin/perl
use v5.42;
use experimental 'class';
class Book {
field $title :param :reader;
field $author :param :reader(written_by);
field $price :param :reader :writer;
field @tags :reader;
method add_tag($tag) {
push @tags, $tag;
return $self;
}
}
my $b = Book->new(title => 'Dune', author => 'Frank Herbert', price => 9.9);
say $b->title;
say $b->written_by;
$b->set_price(12.5)->add_tag('sci-fi')->add_tag('classic');
say $b->price;
say join ', ', $b->tags;
say scalar $b->tags;
A reader is named after the field unless a name is given, as in
:reader(written_by). A writer is named set_ plus the
field name and returns the object, which makes it chainable. A reader for an
array field returns the elements in list context and their count in scalar
context. Fields without these attributes stay completely private.
$ perl reader.pl Dune Frank Herbert 12.5 sci-fi, classic 2
ADJUST blocks
An ADJUST block runs during construction, after the fields have been
initialized. It is the place for validation and for fields computed from
several parameters.
#!/usr/bin/perl
use v5.40;
use experimental 'class';
class Temperature {
field $celsius :param;
field $fahrenheit;
ADJUST {
die "below absolute zero: $celsius\n" if $celsius < -273.15;
$fahrenheit = $celsius * 9 / 5 + 32;
}
method show {
printf "%.1f °C = %.1f °F\n", $celsius, $fahrenheit;
}
}
Temperature->new(celsius => $_)->show for 0, 36.6, -40;
eval { Temperature->new(celsius => -300) };
print "error: $@";
The block rejects impossible temperatures and computes the
$fahrenheit field. Dying in ADJUST aborts the
constructor, so an invalid object is never returned. A class may have several
ADJUST blocks; they run in the order in which they appear, and those
of a parent class run before those of a subclass.
$ perl adjust.pl 0.0 °C = 32.0 °F 36.6 °C = 97.9 °F -40.0 °C = -40.0 °F error: below absolute zero: -300
Inheritance
A class inherits from another with the :isa attribute. Only a
single parent is allowed, and it must itself be declared with
class.
#!/usr/bin/perl
use v5.40;
use experimental 'class';
class Shape {
field $name :param :reader;
method area { 0 }
method describe {
return sprintf "%s with area %.2f", $name, $self->area;
}
}
class Circle :isa(Shape) {
field $r :param;
method area { 3.14159265 * $r ** 2 }
}
class Rectangle :isa(Shape) {
field $w :param;
field $h :param;
method area { $w * $h }
method describe {
my $base = $self->SUPER::describe;
return "$base (${w}x$h)";
}
}
my @shapes = (
Circle->new(name => 'circle', r => 2),
Rectangle->new(name => 'rectangle', w => 3, h => 4),
);
for my $s (@shapes) {
say $s->describe;
say ' isa Shape: ', $s isa Shape ? 'yes' : 'no';
}
Circle and Rectangle override area, and
describe in Shape calls it on $self, so
each shape uses its own version. Rectangle also overrides
describe and calls the parent's version with
SUPER::. The generated constructor accepts the parameters of the
whole hierarchy, here name together with the subclass's own.
Fields are private to the class that declares them: a Rectangle
method cannot see $name and has to call the name
reader. The isa operator tests class membership.
$ perl inherit.pl circle with area 12.57 isa Shape: yes rectangle with area 12.00 (3x4) isa Shape: yes
Private methods
A method declared with my method is lexical: it is visible only
inside the class body and cannot be called from outside. Inside the class, it
is invoked with the ->& operator. Both were added in Perl
5.42.
#!/usr/bin/perl
use v5.42;
use experimental 'class';
class Password {
field $hash;
ADJUST {
$hash = 'unset';
}
my method digest($text) {
my $sum = 0;
$sum = ($sum * 31 + ord) % 1_000_003 for split //, $text;
return sprintf '%06x', $sum;
}
method set($text) {
die "too short\n" if length $text < 8;
$hash = $self->&digest($text);
return $self;
}
method check($text) {
return $self->&digest($text) eq $hash;
}
}
my $pw = Password->new->set('correct horse');
say $pw->check('correct horse') ? 'match' : 'no match';
say $pw->check('battery staple') ? 'match' : 'no match';
eval { $pw->digest('x') };
print "error: $@";
The digest method computes a toy checksum of a string. It is an
implementation detail, so it is lexical: the public methods set
and check call it with $self->&digest(...),
while the call $pw->digest from outside fails because no such
method exists in the package. The checksum only illustrates the technique; real
code would use a proper password hashing module.
$ perl private.pl match no match error: Can't locate object method "digest" via package "Password" at private.pl line 35.
Class data
There is no special syntax for data shared by all objects. A lexical variable
declared with my inside the class block serves the purpose, and a
plain sub can act as a class method.
#!/usr/bin/perl
use v5.40;
use experimental 'class';
class Counter {
my $instances = 0;
field $id = ++$instances;
field $count :param = 0;
sub instances { $instances }
method inc($by = 1) { $count += $by; $self }
method show { say "counter $id: $count" }
}
my $c1 = Counter->new;
my $c2 = Counter->new(count => 10);
$c1->inc->inc;
$c2->inc(5);
$_->show for $c1, $c2;
say 'instances: ', Counter::instances();
say 'instances: ', Counter->instances;
Each new object increments $instances in the initializer of its
$id field, so the objects are numbered. The
instances subroutine is not a method, so it has no
$self and can be called on the class, either as a function or as
Counter->instances; in the second form the class name arrives
as an argument that the subroutine ignores. Calling a real method on the class
name fails with the error Cannot invoke method "show" on a non-instance.
$ perl counter.pl counter 1: 2 counter 2: 15 instances: 2 instances: 2
A stack class
The last example puts the pieces together in a small bounded stack.
#!/usr/bin/perl
use v5.40;
use experimental 'class';
class Stack {
field $limit :param = 5;
field @items;
method push(@values) {
die "stack overflow\n" if @items + @values > $limit;
push @items, @values;
return $self;
}
method pop {
die "stack empty\n" unless @items;
return pop @items;
}
method peek { $items[-1] }
method size { scalar @items }
method is_empty { !@items }
}
my $s = Stack->new(limit => 3);
$s->push(1, 2);
say 'size: ', $s->size;
say 'peek: ', $s->peek;
say 'pop: ', $s->pop;
$s->push(3, 4);
eval { $s->push(5, 6) };
print "error: $@";
say 'size: ', $s->size;
say 'pop: ', $s->pop until $s->is_empty;
eval { $s->pop };
print "error: $@";
The stack keeps its elements in a private array field and its capacity in a
parameter with a default. Methods take signatures, so push accepts
any number of values; it checks the capacity before adding anything, so a
failing call leaves the stack unchanged. Method names may coincide with built-in
functions: inside the class, push @items, ... still calls the
built-in, while $s->push calls the method.
$ perl stack.pl size: 2 peek: 2 pop: 2 error: stack overflow size: 3 pop: 4 pop: 3 pop: 1 error: stack empty
Limitations
The core class system is deliberately small and still evolving. At the time of
writing it has no roles, a class can inherit from only one parent, and that
parent must be a class, not a package with bless.
There is no built-in type checking for fields. Moose and Moo remain the
choice for code that needs roles, type constraints, or support for older Perl
versions; the class feature needs no dependencies and gives real
encapsulation.
Best practices
- Require a recent Perl: use
use v5.40or later so that:readerand__CLASS__are available, anduse experimental 'class'to enable the feature. - Expose only what is needed: add
:readerand:writerto the fields that form the public interface and keep the rest private. - Validate in ADJUST: check parameters there so that invalid objects are never created.
- Prefer immutable objects: fields without writers that are set once in the constructor make objects easier to reason about.
- Use lexical methods for helpers:
my methodkeeps implementation details out of the public interface. - Keep hierarchies shallow: with single inheritance and private fields, composition is often clearer than deep subclassing.
In this article we have used the core Perl class feature: fields
with initializers, constructor parameters with :param, readers and
writers, ADJUST blocks, inheritance with :isa, lexical
methods, and class data.
Source
Author
List all Perl tutorials.