NAME

    Signature::Attribute::Checked - apply value constraint checks to
    subroutine parameters

SYNOPSIS

    With Types::Standard

       use v5.26;
       use Sublike::Extended;
       use Signature::Attribute::Checked;
       use Types::Standard qw( Num );
    
       extended sub add ($x :Checked(Num), $y :Checked(Num)) {
          return $x + $y;
       }
    
       say add(10, 20);            # this is fine
    
       say add("hello", "world");  # throws an exception

DESCRIPTION

    This module provides a third-party subroutine parameter attribute via
    XS::Parse::Sublike, which declares that values passed to a subroutine
    must conform to a given constraint check.

    WARNING The ability for sublike constructions to take third-party
    parameter attributes is still new and highly experimental, and subject
    to much API change in future. As a result, this module should be
    considered equally experimental. Core perl's parser does not permit
    parameters to take attributes. This ability must be requested
    specially; either by using Sublike::Extended, or perhaps enabled
    directly by some other sublike keyword using the XS::Parse::Sublike
    infrastructure.

    Additionally, the behaviour provided by this module should be
    considered more of a work-in-progress stepping stone. Ideally,
    constraint syntax ought to be provided in a much more fundamental way
    by Perl itself, allowing it to be used on my lexicals, class fields,
    and other places as well as subroutine parameters. This module is more
    of a placeholder to allow some part of that behaviour to be specified
    for subroutine parameters, while not getting in the way of a more
    general, more powerful system being added in future.

PARAMETER ATTRIBUTES

 :Checked

       extended sub f($x :Checked(EXPRESSION)) { ... }

    Declares that any value passed to the parameter at the time the
    subroutine is called must conform to the constraint checker specified
    by the expression. Attempts to pass a non-conforming value will throw
    an exception and the subroutine body will not be invoked. Currently
    only scalar parameters are supported.

    At compiletime, the string given by EXPRESSION is eval()'ed in scalar
    context, and its result is stored as part of the subroutine's
    definition. The expression must yield either an object reference, a
    code reference, or a string containing the name of a package. In the
    case of an object or package, a method called check must exist on it.

    If using a plain package name as a checker, be sure to quote package
    names so it will not upset use strict.

       extended sub xyz ($x :Checked('CheckerPackage')) { ... }

    At runtime, this constraint checker is used every time an attempt is
    made to call the function. The checker is used as the invocant for
    invoking a check method, and the value for the parameter is passed as
    an argument. If the method returns true, the call is allowed. If false,
    it is rejected with an exception and the function body is not invoked.

       $ok = $checkerobj->check( $value );  # if an object
    
       $ok = $checkersub->( $value );       # if a code reference
    
       $ok = $checkerpkg->check( $value );  # if a package name

    (For performance reasons, the check method is actually resolved into a
    function at compiletime when the :Checked attribute is applied, and
    this stored function is the one that is called at assignment time. If
    the method itself is replaced later by globref assignment or other
    trickery, this updated function will not be used.)

    As this is the interface supported by Types::Standard, any constraint
    object provided by that module is already supported here.

       use Types::Standard qw( Str Num );
    
       extended sub ghi ($x :Checked(Str), $y :Checked(Num)) { ... }

    It is not specified what order these checks are performed in. In
    particular, if any parameter default expressions invoke any
    side-effects, it is unspecified whether such side-effects will happen
    if a value passed for a parameter fails its constraint check. Users
    should take care not to attempt to invoke any side-effects during such
    expressions.

    Note further that these value checks are only performed once, at the
    time the subroutine is invoked. Code within the body of the subroutine
    can freely assign any other kind of value to the variable corresponding
    to a :Checked parameter without issue.

       extended sub foo ($n :Checked(Num)) {
          $x = "seven";   # this is permitted
       }

SEE ALSO

      * Object::Pad::FieldAttr::Checked - apply value constraint checks to
      Object::Pad fields

AUTHOR

    Paul Evans <leonerd@leonerd.org.uk>

