field#
Declare a per-instance variable inside a class block.
field introduces a new variable whose storage is private to each
object of the enclosing class. Every method and every ADJUST block
of that class sees the field as if it were a lexical in scope at that
point — but the value each sees is the value belonging to the
current instance. Fields are the class feature’s replacement for
hash-slot bookkeeping on a blessed reference.
The feature is still marked experimental in Perl 5.42 (see
Differences from upstream); enable it with
use feature 'class'; and silence the warning category with
no warnings 'experimental::class'; if you don’t want the noise.
Synopsis#
field $scalar;
field $scalar = EXPR;
field @array : ATTRIBUTES;
field %hash : ATTRIBUTES = EXPR;
What you get back#
field is a declaration, not an expression. It produces no value and
cannot appear on the right-hand side of anything. Each field
statement allocates one slot per instance in the class’s layout; the
slot is the field variable itself, bound to a per-object storage
location on entry to any method or ADJUST block.
Scalars, arrays, and hashes are all allowed:
class Thing {
field $scalar = 42;
field @array = qw(this is just an array);
field %hash = (species => 'Martian', planet => 'Mars');
}
Where field declarations are legal#
Only directly inside a class block. field is not a
general-purpose declarator — it is not legal inside a method
body, an ADJUST block, a nested sub, or plain package code.
The compiler rejects it anywhere else:
class C {
field $ok; # OK
method m {
field $nope; # compile error
}
}
A field must be declared before it can be referred to by any method or initializer in the same class body.
Field initializers#
If a = EXPR is present, the expression runs once per constructor
call, after all fields declared earlier in the class body have been
initialized. This matters when a later field’s default depends on
an earlier one:
class WithACounter {
my $next_count = 1;
field $count = $next_count++;
}
Inside an initializer, $self does not exist — the object is
still being built. Use the __CLASS__ token when the initializer
needs the class name (for example, to call a class method that
subclasses can override):
class WithCustomField {
use constant DEFAULT_X => 10;
field $x = __CLASS__->DEFAULT_X;
}
class DifferentCustomField :isa(WithCustomField) {
sub DEFAULT_X { rand > 0.5 ? 20 : 30 }
}
An instance of DifferentCustomField will see __CLASS__ resolve
to its own name, so the initializer picks up the overridden
DEFAULT_X.
Field attributes#
Attributes after a colon control how the field participates in construction and whether accessor methods are generated for it.
:param#
Take the field’s value from a named argument to the constructor:
field $x :param;
field $y :param(the_y_value);
By default the parameter name is the field’s name with the sigil
stripped ($x → x). An explicit name in parentheses overrides
that. Without a defaulting expression the parameter is required
— omitting it from ->new(...) throws. With a defaulting expression
the parameter is optional, and three default operators are
available:
=— default applies only when the caller omitted the parameter.//=— default also applies when the caller passedundef.||=— default also applies when the caller passed a false value.
class Point {
field $x :param = 0; # default if omitted
field $y :param //= 0; # default if omitted or undef
field $z :param ||= 0; # default if omitted, undef, or 0
}
:reader#
Generate a zero-argument accessor method that returns the field. Without an explicit name the method is named after the field (sigil stripped):
field $s :reader;
# equivalent to:
field $s;
method s () { return $s }
An explicit name is allowed:
field $x :reader(get_x); # method get_x () { return $x }
Readers can be applied to array and hash fields too; in list context the method yields the contents, and in scalar context the element count — the usual context behaviour of the underlying variable:
field @users :reader;
...
scalar $instance->users; # count of users
:writer#
Generate a one-argument setter method that assigns its argument to
the field and returns the invocant (to support chaining). The
default method name is the field name (sigil stripped) prefixed with
set_:
field $s :writer;
# equivalent to:
field $s;
method set_s ($new) { $s = $new; return $self }
An explicit name is allowed:
field $x :writer(write_x); # method write_x ($new) { ... }
:writer currently only works on scalar fields; applying it to an
array or hash field is a compile-time fatal error. Build array or
hash writers by hand.
Global state it touches#
None directly. Field storage lives on the instance, and initializer
expressions run in the constructor’s scope — they can read any
variable visible at the point of declaration, but field itself
touches no documented special variable.
Examples#
Minimal class with one field, initialized in ADJUST:
use feature 'class';
no warnings 'experimental::class';
class Greeter {
field $greeting;
ADJUST {
$greeting = "Hello";
}
method say_to ($name) {
say "$greeting, $name";
}
}
Greeter->new->say_to("world"); # Hello, world
Constructor parameters via :param, with a mix of required and
defaulted fields:
class Point {
field $x :param; # required
field $y :param = 0; # optional, defaults to 0
method as_string { "($x, $y)" }
}
Point->new(x => 3)->as_string; # (3, 0)
Point->new(x => 3, y => 4)->as_string; # (3, 4)
Auto-generated accessors cover the common boilerplate:
class Person {
field $name :param :reader;
field $age :param :reader :writer;
}
my $p = Person->new(name => "Ada", age => 36);
$p->name; # "Ada"
$p->age; # 36
$p->set_age(37); # returns $p
Array and hash fields with defaults:
class Bag {
field @items = ();
field %counts;
method add ($item) {
push @items, $item;
$counts{$item}++;
return $self;
}
method unique { keys %counts }
}
Initializer that depends on an earlier field:
class Rect {
field $w :param;
field $h :param;
field $area = $w * $h; # evaluated after $w, $h are set
}
Edge cases#
Lexical visibility is method-scoped, not file-scoped. A field is visible from any
methodorADJUSTblock of the same class, regardless of source file order. It is not visible from plainsubdefinitions inside the class block — only frommethod.Per-instance, not per-class. Two instances of the same class have independent storage for every field. Assigning in one instance does not affect another. If you want class-wide state, use a file-scoped
myvariable outside the field list.Sigil determines type.
field $xis a scalar slot,field @aan array slot,field %ha hash slot. Unlike hash-based objects, there is no way to retype a field at runtime; the slot’s container type is fixed by the sigil at declaration.$selfis unavailable in initializers. The object is not yet constructed when the initializer runs. Use__CLASS__for the class name, and defer anything requiring the full object toADJUST.Initializer order is declaration order. Later initializers may refer to earlier fields; the reverse is a reference to an uninitialized variable.
:writeron non-scalar fields is fatal at compile time. The attribute is defined only for scalars in 5.42; applying it to@arror%haborts compilation of the class.:paramwithout a default is mandatory.Class->new()with the parameter missing throws. Add= EXPR,//= EXPR, or||= EXPRto make it optional.No direct external access. Without
:reader/:writer(or a hand-written method) a field is unreachable from outside the class — that is the encapsulation the class feature provides.Experimental warning. Parsing a
fielddeclaration emits anexperimental::classwarning unless that category is suppressed; see Differences from upstream.
Differences from upstream#
Fully compatible with upstream Perl 5.42. Upstream marks the class
feature — and therefore field — as experimental; pperl tracks the
same status and emits the same experimental::class warning. The
known upstream bugs listed in perlclass (segfaults around
in-file inheritance, refaliasing interactions, and leaky
encapsulation) apply equally to pperl.
See also#
class— declares the class whose body is the only placefieldis legalmethod— the only subroutine form that sees field variables by namemy— ordinary lexical declaration; use it for class-wide state that should not be per-instanceour— package-global declaration; use it for genuinely global state a class wants to exposebless— the pre-5.38 way to build objects;fieldreplaces the hash-slot bookkeeping thatbless-based classes neededref— check an object’s class at runtime; still works on instances produced by aclassconstructor