Skip to content

Implement Function::Parameters compatibility using native signatures and parser support #1361

Description

@fglock

Summary

Implement a PerlOnJava-compatible Function::Parameters provider that uses
PerlOnJava's parser/compiler infrastructure and modern Perl signatures/class
semantics where they match the module's behavior.

This is a focused consumer/port issue for the parser extension capability
proposed in #1292. It should not attempt to reproduce the Perl 5 parser ABI or
compile the module's native XS code.

Motivation and evidence

Function::Parameters is currently blocked because its latest CPAN release,
v2.002006 (2025-08-16), loads an XS implementation. The XS code installs a
Perl keyword plugin, parses declarations such as fun and method, creates
lexical parameter bindings, emits default and validation logic, and exposes
signature metadata through Function::Parameters::Info.

The CPAN reverse-dependency lookup reports 53 unique dependant distributions,
including 8 released within the last three years. Examples include
exact-fun, Data-Frame, WebService-OpenStates,
Net-Google-CivicInformation, App-Wax, HTML-Blitz, Klonk, and
Function-Return.

The CPAN compatibility run 20260910-101908-8428 showed
Mojolicious::Plugin::GraphQL failing before its own behavior was tested:
Function::Parameters could not load because no Java XS implementation was
available. Other dependency paths have the same underlying limitation.

Feasibility

A normal pure-Perl replacement is not sufficient. Function::Parameters adds
custom declaration keywords and relies on compile-time parser/optree behavior;
ordinary import, AUTOLOAD, or runtime wrappers cannot reliably make syntax
such as this work:

use Function::Parameters;
fun add($x, $y = 1) { $x + $y }
method render($self: :$format = 'html') { ... }

Source filters could rewrite a subset, but would be fragile around eval,
lexical pragma scope, nested declarations, heredocs, diagnostics, and generated
closures. They would also make JVM/interpreter behavior depend on a second
parser.

Modern Perl provides useful semantics but not a drop-in replacement:

  • Stable core signatures (enabled by use v5.36) cover positional parameters,
    defaults, slurpy arrays/hashes, and argument-count checking.
  • The experimental class feature provides class, field, method,
    ADJUST, and field :param constructor arguments.
  • Core signatures do not provide the complete Function::Parameters keyword
    model, arbitrary configured invocants, fun, named :$x parameters with
    the same rules, custom type constraints/coercions, method modifiers, or the
    Function::Parameters::Info API.

References:

Conclusion: a mostly-Perl compatibility layer is feasible, but it requires
PerlOnJava parser/compiler support. It is not feasible as a standalone pure
Perl module with no engine changes.

Proposed architecture

  1. Use Design a parser keyword-plugin API for PerlOnJava #1292's lexical parser keyword-plugin API to register fun, method,
    configured aliases, and later modifiers.
  2. Parse declarations directly into the shared AST used by both execution
    backends. Do not generate backend-specific implementations.
  3. Normalize supported signatures into existing subroutine nodes, including
    lexical bindings, invocants, defaults, slurpy parameters, and call-time
    validation.
  4. Represent signature metadata in a stable compiler/runtime structure so
    Function::Parameters::info can expose it without inspecting backend
    internals.
  5. Implement the compatibility module as a small Perl provider/pragma that
    requests parser registration. Its API should degrade with a clear
    diagnostic for unsupported syntax rather than silently treating fun or
    method as ordinary barewords.

Suggested implementation phases

Phase 1: core signature subset

  • fun named and anonymous declarations;
  • ordinary required and optional positional parameters;
  • default expressions, including //= and ||= forms;
  • ignored parameters and slurpy @/% parameters;
  • exact argument-count diagnostics;
  • lexical pragma scope for use/no and nested eval.

Where semantics are identical, reuse the existing core-signature AST/runtime
representation rather than creating a parallel implementation.

Phase 2: methods and metadata

  • method declarations;
  • implicit, named, and configured invocants;
  • class-method and multi-invocant configurations where needed;
  • Function::Parameters::Info objects and parameter categorization;
  • prototypes and relevant subroutine attributes.

Phase 3: extended behavior

  • named :$parameter arguments and named-parameter slurping;
  • custom type constraints, inline checks, custom error messages, and coercion;
  • before, after, around, augment, and override method modifiers;
  • closure/lifetime behavior and debugger/source-location parity.

Compatibility boundaries

The first implementation should document any behavior that cannot be matched
exactly. In particular, do not claim complete compatibility until the following
are covered or explicitly rejected:

  • compile-time syntax errors and line/column locations;
  • indirect calls and prototype interactions;
  • recursion and anonymous functions;
  • default expressions evaluated at call time;
  • aliases and mutation behavior through @_;
  • typed parameters and custom type objects;
  • modifier composition and method cache invalidation;
  • eval STRING, nested lexical scopes, and require-time registration;
  • info() introspection and generated parameter metadata;
  • JVM/interpreter parity.

Testing and acceptance criteria

Add project-owned tests without modifying upstream tests. Validate each
Perl-level behavior with system Perl first, then require both PerlOnJava
backends to pass.

Acceptance should include:

  • parser-plugin registration and lexical removal;
  • named and anonymous fun declarations;
  • methods with invocants and defaults;
  • positional, named, ignored, and slurpy parameters;
  • malformed declarations and stable source locations;
  • nested blocks, strings, comments, heredocs, and eval;
  • default-expression side effects and recursive calls;
  • Function::Parameters::Info compatibility for the supported subset;
  • identical JVM/interpreter results;
  • a minimal Mojolicious::Plugin::GraphQL or GraphQL dependency reproducer;
  • progress toward the blocked CPAN dependants, with unsupported XS-only cases
    kept separately classified.

The issue is complete only when the provider can execute a documented useful
subset on both backends, the parser API is documented, and remaining upstream
failures have an explicit compatibility classification.

Related: #1292 (parser keyword-plugin API).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:cpan-portCPAN compatibility ports and providersarea:parserParsing compilation AST and eval behaviorenhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions