August 20, 2023·4 min read·engineeringperlobjectsinheritance

Perl's __CLASS__ preserves runtime dispatch during field initialization

Perl 5.39.2 adds a class-aware token for methods and field initializers. It lets inherited initialization call subclass behavior before an instance is ready to expose as self.

A field initializer in a base class knows where its source code lives. That is not necessarily the class whose object is being constructed. If initialization hardcodes the defining package, a subclass cannot change a default through normal method dispatch. If it uses the unfinished instance, construction has to expose an object before that object is ready.

Perl 5.39.2 supplies __CLASS__ for this distinction. The August 20 release entry identifies the development snapshot. Its release notes say the token is available in methods, ADJUST blocks, and field initializer expressions. It yields the runtime class of the instance, including when the source belongs to a base class.

I find this a more useful addition than another way to spell a package name. Perl's native class work is establishing the rules around construction and private state. A class-aware expression fills a specific gap where ordinary lexical package identity supplies the wrong answer.

Package identity and instance identity differ

The function reference at this version describes __PACKAGE__ as the name of the package containing the expression. That remains useful when the intention is to refer to the defining package itself. Inheritance does not relocate that source code into the subclass.

__CLASS__ answers a different question. In a method it is essentially equivalent to ref($self), according to the reference. It identifies the invoking instance's class. Its additional role is to make that identity available during field initialization, where $self is unavailable because the instance is not yet fully constructed.

The difference may be invisible when a class has no subclass. Both expressions can yield the same name. An example confined to that case would therefore conceal the behavior that motivated the new token. Constructing a subclass makes the dispatch decision observable.

A base initializer can call a subclass default

The version's class reference demonstrates a base field initialized through a class method, followed by a subclass overriding that method. This example follows the same documented mechanism with a constant result:

use v5.38;
use feature 'class';
no warnings 'experimental::class';

class BaseLimit {
    field $limit = __CLASS__->default_limit;

    sub default_limit { 10 }
    method limit { return $limit; }
}

class LargerLimit :isa(BaseLimit) {
    sub default_limit { 20 }
}

say BaseLimit->new->limit;
say LargerLimit->new->limit;

The expected values are 10 and 20. The initializer text belongs to BaseLimit in both constructions. When constructing LargerLimit, __CLASS__ yields that subclass name and the method lookup finds its override. The field remains part of the base class's declaration.

The helper uses sub, while the accessor uses method. This follows the reference's class-method examples. The default provider receives a class invocant through ordinary method-call syntax. The accessor operates on a constructed instance and reads its private field.

No instance escapes through $self to make this work. The initializer gets the class name it needs, then calls behavior using that class. A class name can select the override without implying that all fields of an unfinished object are available.

Field privacy remains lexical

The class reference says fields belong to the declaring class's lexical scope. Inherited methods remain callable, but a subclass cannot directly name its parent's private fields. The new token does not change that visibility rule.

In the example, the subclass supplies a different default without accessing $limit. The base initializer controls assignment to that field, and the base accessor controls reading it. This is a useful combination of extensible behavior and private representation. The subclass's contribution is the value returned by a class method.

That distinction matters when choosing an extension point. A base class using runtime class dispatch is allowing subclasses to influence construction. A base class using a fixed package name is selecting a particular implementation. Neither expression is an interchangeable shorthand for the other once inheritance is involved.

Default expressions themselves still run as part of each instance's construction. The documented ability to read previously initialized fields remains separate from this class identity. A runtime class name does not change initializer ordering or grant access to fields that have not been established.

The token has a defined context

The release notes locate __CLASS__ within the native class facility. They do not present it as a general replacement for __PACKAGE__ in arbitrary Perl source. The relevant contexts have an invoking or constructing instance whose class the interpreter can identify.

The existing construction lifecycle also distinguishes field initialization from adjustment. ADJUST code has access to $self, while field initialization does not expose that lexical. Allowing the token in both contexts gives a consistent way to express class identity even though the surrounding instance access differs.

I regard that consistency as useful for reading inherited code. A method or initializer can state that dispatch should follow the actual class. A reader no longer has to infer that intention from a hand-written attempt to recover a receiver during construction.

The class system remains experimental in this development release. The immediate change is nevertheless precise. Perl 5.39.2 lets an inherited initializer ask the runtime class for a default while preserving the rule that an incompletely constructed instance is unavailable as $self.