ADR-003: Params::Util::Assert -- assertion variants

Status

Proposed

Context

Params::Util predicates return the value on success or undef on failure. Callers that want to die on invalid input must wrap each check:

my $obj = _INSTANCE($val, 'Foo') or croak "expected a Foo";

This pattern is repetitive. An assertion module that dies directly would be more ergonomic and -- in XS -- more efficient, since it avoids the Perl-level conditional after the ->isa / ->can call.

Decision

Deferred. Ship Params::Util::Assert as a separate module within the same distribution once the interface stabilises. Key open questions:

Error behaviour

croak vs carp vs throwing a structured exception object. Different consumers need different behaviour; a single hard-coded croak does not serve them all.

Error message content

Minimally useful: the predicate name and the failing value's type. Maximally useful: parameter name, expected type, caller context. The richer the message, the more the interface must accept (extra arguments or configuration).

Batch validation

Validating all parameters up front and collecting all failures (rather than dying on the first) is common in form/API validation. This fundamentally changes the control flow and may warrant a separate interface rather than extending the per-parameter assertion.

XS integration

A direct croak from XS avoids the return-check-croak round-trip. However, baking error-message formatting into C makes the module harder to extend. A possible middle ground: XS performs the check and calls a configurable Perl-level formatter only on the failure path.

Relationship to type systems

Type::Tiny, Specio, and Moose type constraints already provide assertion semantics. Params::Util::Assert should complement rather than compete -- it targets the lightweight, no-dependency niche where full type systems are overkill.

Consequences

  • No code ships until a concrete consumer clarifies the interface requirements.

  • When implemented, the module lives in lib/Params/Util/Assert.pm within the Params-Util distribution -- no separate dist, no runtime pollution for users who do not load it.

  • XS acceleration is desirable but must not lock in an error-reporting strategy that cannot be overridden from Perl.

  • The Assert interface should be designed with ADR-002 in mind: if multi-method _CAN / _DOES variants exist, the assertion should report which specific method or role was missing.