# Modern classes The [`class`](../../p5/core/perlfunc/class) feature is the recommended way to write object-oriented code in pperl. It replaces the hand-rolled constructor, the manual accessor generation, the hash-slot bookkeeping, and the `use parent` dance with a single declarative syntax. You describe *what* the class is; the runtime arranges *how* it is implemented. This chapter walks through the feature as a working programmer would meet it: first a minimum class, then fields and attributes, then methods, then construction-time hooks, then inheritance. Each section is short on purpose; when you want the full surface of a keyword, follow the cross-link into its reference page. ## Enabling the feature The feature is flagged experimental in Perl 5.42 and pperl mirrors that status. Every file that uses it opens with: ```perl use v5.38; use feature 'class'; no warnings 'experimental::class'; ``` The `use v5.38` line already enables the `class` feature on its own, but being explicit makes the dependency visible to anyone reading the file. ## A minimal class ```perl use v5.38; use feature 'class'; no warnings 'experimental::class'; class Point { field $x :param; field $y :param; method distance_from_origin { return sqrt($x ** 2 + $y ** 2); } } my $p = Point->new(x => 3, y => 4); say $p->distance_from_origin; # 5 ``` Three things to notice: - There is no `sub new`. The runtime generates the constructor from the [`field`](../../p5/core/perlfunc/field) declarations. A user-written `sub new` inside a `class` body is a compile-time error on purpose — the generated one knows how to wire up `:param`, run initialisers, and trigger `ADJUST` blocks in the right order. - Fields are referenced by their *declared name* inside methods, not through `$self->{x}`. The instance storage is genuinely private; no code outside the class body can poke at it. - The [`method`](../../p5/core/perlfunc/method) keyword takes care of `$self`. You never write `my $self = shift`. ## Fields A [`field`](../../p5/core/perlfunc/field) is per-instance storage. Every object of the class gets its own slot; every method and every `ADJUST` block sees the field as if it were a lexical. ```perl class Counter { field $value = 0; field $step = 1; method tick { $value += $step } method value { $value } } ``` Fields accept scalars, arrays, and hashes: ```perl class Registry { field $name; field @items; field %seen; } ``` ### Attributes on fields Field attributes take the declarative work off your hands. - **`:param`** — bind this field to a constructor argument. If the caller omits it, the field is either left unset or takes the declared default. - **`:param(alt)`** — bind to a different constructor name. - **`:reader`** — generate a read-only accessor with the field's name minus the sigil. - **`:reader(custom)`** — generate a reader under a different name. - **`:writer`** — generate a setter (`set_FIELDNAME`). ```perl class User { field $name :param :reader; field $email :param :reader :writer; field $role :param :reader = 'guest'; } my $u = User->new(name => 'Ada', email => 'ada@example.org'); say $u->name; # Ada $u->set_email('ada@analytical.org'); say $u->role; # guest ``` ### Default values Defaults use one of three operators, each with a different rule: - **`=`** — apply when the caller *omitted* the parameter entirely. - **`//=`** — also apply when the caller passed `undef`. - **`||=`** — also apply when the caller passed any false value. ```perl class Window { field $title :param = 'untitled'; field $width :param //= 640; field $shown :param ||= 1; } ``` Pick `=` unless you have a concrete reason to allow the stronger forms. Silent promotion of `undef` or `0` to a default is a bug magnet. ### Fields are not lexicals in the usual sense Fields look like lexicals inside a method body, but they have tighter rules: - You cannot [`our`](../../p5/core/perlfunc/our) a field, you cannot [`local`](../../p5/core/perlfunc/local) one, and you cannot take a reference to one and export it. - Fields are private to the class. Subclasses do **not** inherit a parent's fields; if a subclass needs a parent's state, it asks for it through a method. - A field's initialiser runs before `$self` is bound. Inside `field $x = EXPR`, you can use earlier fields by name and you can use `__CLASS__`, but you cannot use `$self`. Anything that needs the fully constructed instance belongs in an `ADJUST` block. ## Methods A [`method`](../../p5/core/perlfunc/method) is a subroutine that auto-binds `$self` and reads the enclosing class's fields by name. ```perl class File { field $path :param :reader; method slurp { open my $fh, '<', $path or die "open $path: $!"; local $/; return <$fh>; } method rename ($new) { rename $path, $new or die "rename: $!"; $path = $new; } } ``` Methods use signatures automatically — `use feature 'signatures'` is implied inside a class body. `$self` is the method's implicit first argument and does **not** appear in the signature. ### Private methods A method declared with `my` is lexical to the class body and is invoked through the `->&` operator: ```perl class Safe { field $secret :param; my method check ($n) { $n == $secret } method unlock ($n) { return $self->&check($n) ? 'open' : 'denied'; } } ``` `my method` is the closest pperl has to a hard-private method; no external caller can reach it because the name does not live in the package at all. ## Construction hooks: `ADJUST` An `ADJUST` block runs after field initialisation, with `$self` already bound. It is the place for: - Post-construction validation. - Derived fields that depend on other fields. - Opening a handle or connecting to a resource whose lifetime matches the object. ```perl class TempFile { field $prefix :param = 'tmp'; field $path; field $fh; ADJUST { $path = "/tmp/$prefix-$$-" . int(rand 1_000_000); open $fh, '>', $path or die "open $path: $!"; } method write ($data) { print {$fh} $data } method path { $path } } ``` Multiple `ADJUST` blocks in one class run in declaration order. In an inheritance chain, the parent's `ADJUST` blocks run before the child's. ## Inheritance A class inherits from at most one parent using the `:isa` attribute: ```perl class Shape { field $colour :param :reader = 'black'; method area { 0 } } class Circle :isa(Shape) { field $radius :param :reader; method area { 3.14159265 * $radius ** 2 } } ``` Only **methods** are inherited. Fields are per-class storage. A subclass that needs the parent's state asks through a reader: ```perl class Labelled :isa(Shape) { field $label :param :reader; method describe { "$label (" . $self->colour . ')' } } ``` Multiple inheritance is not supported. `:isa(A, B)` is a syntax error, and a class cannot carry more than one `:isa` attribute. The [inheritance chapter](inheritance) explains why, and covers the role-based alternative. ### Calling up the chain `SUPER::` still works, exactly as it does for [`bless`](../../p5/core/perlfunc/bless)-based classes: ```perl class Dog :isa(Animal) { method introduce { $self->SUPER::introduce; say "and I can fetch"; } } ``` ## `__CLASS__` Inside a field initialiser or a method body, `__CLASS__` is the class currently being constructed. In a subclass, `__CLASS__` refers to the subclass even inside an inherited method or an inherited field initialiser. Use it for factory-style hooks: ```perl class Base { sub DEFAULT_X { 10 } field $x = __CLASS__->DEFAULT_X; method x { $x } } class Tuned :isa(Base) { sub DEFAULT_X { 99 } } say Tuned->new->x; # 99 ``` ## Interoperation with classical OO A `class`-declared class is a regular package. Code that uses [`ref`](../../p5/core/perlfunc/ref), the [`isa`](../../p5/core/perlfunc/isa) operator, `UNIVERSAL::isa`, and `UNIVERSAL::can` keeps working: ```perl my $c = Circle->new(radius => 2); say ref $c; # Circle say $c isa Shape ? 'yes' : 'no'; # yes say $c->can('area') ? 'yes' : 'no'; # yes ``` A classical class can subclass a modern class and vice versa, as long as the classical side goes through methods (never through `$self->{fieldname}`) — see the [migration chapter](migrating) for the full interop story. ## Edge cases worth knowing - **Do not write `sub new`.** The constructor is generated. A user-written `new` inside a `class` body is rejected at compile time. - **Treat `@ISA` as read-only** for `class`-declared classes. Runtime manipulation is undefined behaviour. - **`$self` is read-only** inside a method. Assigning to `$self` is a runtime error. - **`package` cannot reopen a class.** Once a namespace has been declared with `class`, a later [`package`](../../p5/core/perlfunc/package) statement for the same name is a compile-time error, and vice versa. - **Statement-form scope.** `class Foo;` consumes the rest of the enclosing block, typically the rest of the file. A subsequent `class` or [`package`](../../p5/core/perlfunc/package) ends the body; there is no way to close a statement-form class early. ## Where to go next - [Inheritance and method resolution](inheritance) — the full story of how method lookup works across `:isa` chains and across mixed classical/modern hierarchies. - [Roles and delegation](roles-and-delegation) — the recommended answer to "I want to share behaviour across unrelated classes." - [Migrating from classical to modern](migrating) — if you are staring at a `bless`-based class and wondering what the equivalent `class` block looks like.