July 3, 2025·6 min read·engineeringperlclassescompatibility

Perl 5.42 adds lexical methods and explicit source encoding

Lexical methods give Perl's class experiment private helpers through lexical binding. Source-encoding checks and retained smartmatch features make the release's compatibility choices explicit.

A helper method called by name participates in method lookup, even when its author intended it only for use inside a class. Perl 5.42 adds a different way to express that relationship. A method declared with my method has lexical visibility, and the new ->& invocation operator calls a lexical subroutine as a method without ordinary name-based resolution.

The release notes describe the combination as providing the effect of private methods. The history records date the stable release to July 3. Its other changes include explicit source-encoding declarations and experimental list predicates, alongside a decision to retain switch and smartmatch under feature controls.

I still prefer Perl for one-off text work, where its grammar makes matching and substitution direct. Larger programs require more attention to visibility and source conventions. These additions interest me because they put some of those decisions into declarations the interpreter can enforce, without requiring every existing program to adopt the new class syntax.

Lexical binding controls which helper gets called

The 5.42 class documentation demonstrates a lexical method inside a class and invokes it through $self->&name(...). The helper is visible where its lexical declaration is in scope. Code outside that scope cannot obtain it merely by using its source-level name as an ordinary public method.

That is a stronger statement than a naming convention. Giving a public method a name that suggests internal use still leaves it in the name-based method system. A lexical helper has a different binding rule. The call identifies the lexical subroutine directly, while using the invocant needed for method behavior.

The release notes separate declaration and invocation because both are needed to explain the result. Declaring the method lexically establishes visibility. Calling it through ->& bypasses ordinary name lookup. Describing only one half would leave the reader uncertain whether the implementation still searches for a package method with the same spelling.

A compact example follows the documented form and keeps the experimental class declaration explicit.

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

class Message {
    my method render ($text) {
        return "message=$text";
    }

    method format ($text) {
        return $self->&render($text);
    }
}

say Message->new->format("ready");

The public format method can call its lexical helper within the class scope. The example does not need to put render into the ordinary public method namespace. Its relationship to format is visible from the declaration and call syntax, so a reader can identify the binding without interpreting an informal privacy convention.

This does not turn the experimental class facility into a claim of a security boundary against hostile code. The documented purpose concerns method visibility and lookup. It gives class authors a way to keep internal calls bound to lexical declarations, which is useful independently of any broader claim about isolating untrusted execution.

Field writers add a separate kind of method

The class changes also include :writer for scalar fields. Release-note examples show it alongside :reader and :param, with a generated set_x method updating a field named $x. The class documentation says a writer consumes exactly one argument and assigns it to the field.

This addition concerns public access to state, while lexical methods concern visibility of implementation helpers. They solve different problems even though both create or invoke methods. An automatically generated writer is appropriate when assigning the supplied scalar is the intended operation. A helper can remain lexical when it exists to support another method's implementation.

The distinction matters to a class's interface. Adding a writer makes mutation available through a method. Making a helper lexical reduces dependence on the ordinary method namespace for that internal call. Neither declaration supplies the other's policy, so they should be evaluated according to the behavior each one actually introduces.

The documented writer signature is also a useful limit. It describes assigning one argument to a scalar field. It does not claim that arbitrary domain validation appears automatically with the accessor. If mutation requires additional rules, the decision about exposing a simple generated writer remains part of the class design.

Source encoding is checked within lexical scope

The new source::encoding pragma accepts ascii and utf8. Its UTF-8 form is equivalent to use utf8, while the ASCII form lets the interpreter reject source that exceeds the declared encoding policy. The release notes say the purpose is to catch cases where a programmer forgot to enable UTF-8 source.

This concerns the program's source representation. A text file read at runtime has its own encoding decisions, which this declaration does not replace. A source string literal containing non-ASCII characters and an external byte stream are different inputs to the interpreter and application. Giving the source policy a name makes that distinction easier to state.

An ASCII source policy is automatically enabled within the scope of a version declaration for 5.41.0 or later. Adopting the newer language bundle can therefore produce a diagnostic in a source file that previously lacked an explicit encoding declaration. The executable version alone does not describe which lexical rules a file requested.

The release permits no source::encoding to disable checking for the rest of its scope. Its notes say non-ASCII characters then have undefined meaning. That option describes an unchecked state, while declaring UTF-8 expresses a defined source encoding. The choice matters when making a source file's intended interpretation explicit.

My preference is for the declaration that states the file's actual encoding. Perl's compact expressions already demand attention to context, so source representation should not add another unstated assumption. The new pragma allows that decision to appear near the code whose parsing it governs.

Smartmatch remains available

Perl 5.42 does not remove switch or smartmatch. The release notes explain that both were deprecated in 5.38 and scheduled for removal, but that removal has been postponed indefinitely after extensive discussion. Their use no longer produces the deprecation warning described by that earlier schedule.

The retained implementation still has feature boundaries. Switch requires the switch feature, which newer bundles do not enable by default. Smartmatch now requires smartmatch, enabled by default and by older bundles through 5.40, while the 5.41 bundle and later disable it. A program can explicitly enable either feature where it needs the operation.

This arrangement separates continued interpreter support from the syntax selected by a new version declaration. Existing availability does not imply inclusion in every new bundle. Conversely, a feature being disabled in a lexical scope does not mean the interpreter has removed it. That distinction is necessary for an accurate account of compatibility in this release.

The apostrophe package separator follows another explicit control. It has been reinstated by default after removal during development, with a feature that can disable its use in source. Symbolic references continue their internal apostrophe conversion. The release notes distinguish those paths instead of claiming that one syntax setting rewrites every internal naming behavior.

List predicates stay experimental

The new any and all operators ask whether any or every list element satisfies a block predicate. They return Boolean answers and stop once the result is determined. Their feature names are keyword_any and keyword_all, chosen to avoid confusion with the feature pragma's :all bundle.

The release notes say these core operators avoid an additional subroutine call frame for invoking the block. That is a concrete implementation difference from the same-named library functions that inspired them. It also means their introduction deserves attention to invocation behavior, beyond viewing the keywords as shorter imports.

The short-circuit rule is useful when comparing a predicate to a count. A count of matching elements requires examining the elements needed to produce that count. An existential predicate has its answer as soon as one element satisfies the condition. A universal predicate has its answer as soon as one element fails. Programs whose blocks have observable effects need to account for those different invocation counts.

The operator choice therefore records an evaluation requirement as well as an intention. A reader seeing any knows that the expression asks for existence, without needing a complete count of successful elements. Choosing all expresses the universal condition, with its own early failure behavior. The explicit feature guard makes adoption of those semantics visible in the source file.

These operators remain experiments requiring explicit feature requests. Their presence in a stable interpreter release does not remove that status. Perl 5.42 therefore combines a stable release vehicle with individually experimental capabilities, while its lexical declarations identify where new syntax and stricter source rules apply.