Type::Params(3)

๐Ÿ’– Type::Params(3) ๐Ÿ’–

okay bestie, this is the User Contributed Perl Documentation for Type::Params, and it is a lot โ€” but we're gonna get through it together ๐Ÿซถ no cap.


โœจ NAME โœจ

Type::Params โ€” sub signature validation using Type::Tiny type constraints and coercions ๐Ÿ’…


๐ŸŒธ SYNOPSIS ๐ŸŒธ

use v5.36;
use builtin qw( true false );

package Horse {
  use Moo;
  use Types::Standard qw( Object );
  use Type::Params -sigs;
  use namespace::autoclean;

  ...;   # define attributes, etc

  signature_for add_child => (
    method     => true,
    positional => [ Object ],
  );

  sub add_child ( $self, $child ) {
    push $self->children->@*, $child;
    return $self;
  }
}

package main;

my $boldruler = Horse->new;

$boldruler->add_child( Horse->new );

$boldruler->add_child( 123 );   # dies (123 is not an Object!)

๐Ÿฆ‹ STATUS ๐Ÿฆ‹

This module is covered by the Type-Tiny stability policy. periodt. ๐Ÿ’…


๐Ÿ’– DESCRIPTION ๐Ÿ’–

This documents the details of the Type::Params package. Type::Tiny::Manual is a better starting place if you're new. iykyk โœจ

Type::Params uses Type::Tiny constraints to validate the parameters to a sub. It takes the slightly unorthodox approach of separating validation into two stages:

  1. Compiling the parameter specification into a coderef; then
  2. Using the coderef to validate parameters.

The first stage is slow (it might take a couple of milliseconds), but only needs to be done the first time the sub is called. The second stage is fast; according to my benchmarks faster even than the XS version of Params::Validate. lowkey iconic fr fr ๐Ÿ”ฅ

With the modern API, you rarely need to worry about the two stages being internally separate.

Note that most of the examples in this documentation use modern Perl features such as subroutine signatures, postfix dereferencing, and the "true" and "false" keywords from builtin. On Perl version 5.36+, you can enable all of these features using:

use v5.36;
use experimental 'builtin';
use builtin 'true', 'false';

Type::Params does support older versions of Perl (as old as 5.8), but you may need to adjust the syntax for some examples. ๐Ÿงš


๐ŸŒˆ MODERN API ๐ŸŒˆ

The modern API can be exported using:

use Type::Params -sigs;

Or:

use Type::Params -v2;

Or by requesting functions by name:

use Type::Params qw( signature signature_for );

Two optional shortcuts can be exported:

use Type::Params qw( signature_for_func signature_for_method );

Or:

use Type::Params -sigplus;

๐ŸŽ€ signature_for $function_name => ( %spec ) ๐ŸŽ€

Wraps an existing function in additional code that implements all aspects of the subroutine's signature, including unpacking arguments from @_, applying default values, coercing, and validating values. it's giving thorough ๐Ÿ’…

signature_for( \@functions, %opts ) is a useful shortcut if you have multiple functions with the same signature.

signature_for [ 'add_nums', 'subtract_nums' ] => (
  positional => [ Num, Num ],
);

Although normally used in void context, signature_for does return a value.

my $meta = signature_for add_nums => (
  positional => [ Num, Num ],
);

sub add_nums ( $x, $y ) {
  return $x + $y;
}

Or when used with multiple functions:

my @metas = signature_for [ 'add_nums', 'subtract_nums' ] => (...);

This is a blessed Type::Params::Signature object which provides some introspection possibilities. Inspecting $meta->coderef->code can be useful to see what the signature is doing internally. ๐Ÿ‘‘

Signature Specification Options

The signature specification is a hash which must contain either a "positional", "named", or "multiple" key indicating whether your function takes positional parameters, named parameters, or supports multiple calling conventions, but may also include other options.

"positional" ArrayRef

This is conceptually a list of type constraints, one for each positional parameter. For example, a signature for a function which accepts two integers:

signature_for myfunc => ( positional => [ Int, Int ] );

However, each type constraint is optionally followed by a hashref of options which affect that parameter. For example:

signature_for myfunc => ( positional => [
  Int, { default => 40 },
  Int, { default =>  2 },
] );

Type constraints can instead be given as strings, which will be looked up using "dwim_type" from Type::Utils.

signature_for myfunc => ( positional => [
  'Int', { default => 40 },
  'Int', { default =>  2 },
] );

See the section below for more information on parameter options.

Optional parameters must follow required parameters, and can be specified using either the Optional parameterizable type constraint, the "optional" parameter option, or by providing a default.

# All three parameters are effectively optional.
signature_for myfunc => ( positional => [
  Optional[Int],
  Int, { optional => true },
  Int, { default  => 42 },
] );

A single slurpy parameter may be provided at the end, using the Slurpy parameterizable type constraint, or the "slurpy" parameter option:

signature_for myfunc => ( positional => [
  Int,
  Slurpy[ ArrayRef[Int] ],
] );

signature_for myfunc => ( positional => [
  Int,
  ArrayRef[Int], { slurpy => true },
] );

The "positional" option can also be abbreviated to "pos".

So "signature_for myfunc => ( pos => [...] )" can be used instead of the longer "signature_for myfunc => ( positional => [...] )".

signature_for add_numbers => ( pos => [ Num, Num ] );

sub add_numbers ( $num1, $num2 ) {
  return $num1 + $num2;
}

say add_numbers( 2, 3 );   # says 5

"named" ArrayRef

This is conceptually a list of pairs of names and type constraints, one name+type pair for each named parameter. For example, a signature for a function which accepts two integers:

signature_for myfunc => ( named => [ foo => Int, bar => Int ] )

However, each type constraint is optionally followed by a hashref of options which affect that parameter. For example:

signature_for myfunc => ( named => [
  foo => Int, { default => 40 },
  bar => Int, { default =>  2 },
] );

Type constraints can instead be given as strings, which will be looked up using "dwim_type" from Type::Utils.

signature_for myfunc => ( named => [
  foo => 'Int', { default => 40 },
  bar => 'Int', { default =>  2 },
] );

Optional and slurpy parameters are allowed, but unlike positional parameters, they do not need to be at the end. โœจ

See the section below for more information on parameter options.

If a signature uses named parameters, the values are supplied to the function as a single parameter object:

signature_for add_numbers => ( named => [ num1 => Num, num2 => Num ] );

sub add_numbers ( $arg ) {
  return $arg->num1 + $arg->num2;
}

say add_numbers(   num1 => 2, num2 => 3   );   # says 5
say add_numbers( { num1 => 2, num2 => 3 } );   # also says 5

Since Type::Params 2.009_000 the $arg object has methods called "__TO_LIST__", "__TO_ARRAYREF__", and "__TO_HASHREF__".

signature_for add_numbers => ( named => [ num1 => Num, num2 => Num ] );
sub add_numbers ( $arg ) {
  my ( $num1, $num2 ) = $arg->__TO_LIST__;
  return $num1 + $num2;
}

signature_for add_numbers => ( named => [ num1 => Num, num2 => Num ] );
sub add_numbers ( $arg ) {
  my $nums = $arg->__TO_ARRAYREF__;
  return $nums->[0] + $nums->[1];
}

signature_for add_numbers => ( named => [ num1 => Num, num2 => Num ] );
sub add_numbers ( $arg ) {
  my $nums = $arg->__TO_HASHREF__;
  return $nums->{num1} + $nums->{num2};
}

Each of these can be given an optional arrayref indicating which fields to return.

signature_for add_numbers => ( named => [ num1 => Num, num2 => Num ] );
sub add_numbers ( $arg ) {
  my ( $num2, $num1 ) = $arg->__TO_LIST__( [ qw/ num2 num1 / ] );
  return $num1 + $num2;
}

The arrayref accepts aliases (see "alias") but methods may throw an exception if the arrayref contains unknown field names. (See "strictness" to control whether an exception is thrown.)

These methods start and end with double underscores to reduce the chance that they'll conflict with the name of a named parameter, however they are considered part of the public, supported API.

The object overloads "@{}" to call "__TO_ARRAYREF__".

"named_to_list" ArrayRef|Bool

The "named_to_list" option is ignored for signatures using positional parameters, but for signatures using named parameters, allows them to be supplied to the function as a list of values instead of as a single object:

signature_for add_numbers => (
  named         => [ num1 => Num, num2 => Num ],
  named_to_list => true,
);

sub add_numbers ( $num1, $num2 ) {
  return $num1 + $num2;
}

say add_numbers(   num1 => 2, num2 => 3   );   # says 5
say add_numbers( { num1 => 2, num2 => 3 } );   # also says 5

You can think of "add_numbers" above as a function which takes named parameters from the outside, but receives positional parameters on the inside.

You can use an arrayref to control the order in which the parameters will be supplied. (By default they are returned in the order in which they were defined.)

signature_for add_numbers => (
  named         => [ num1 => Num, num2 => Num ],
  named_to_list => [ qw( num2 num1 ) ],
);

sub add_numbers ( $num2, $num1 ) {
  return $num1 + $num2;
}

say add_numbers(   num1 => 2, num2 => 3   );   # says 5
say add_numbers( { num1 => 2, num2 => 3 } );   # also says 5

"list_to_named" Bool

For a function that accepts named parameters, allows them to alternatively be supplied as a list in a hopefully do-what-you-mean manner.

signature_for add_numbers => (
  named         => [ num1 => Num, num2 => Num ],
  list_to_named => true,
);

sub add_numbers ( $arg ) {
  return $arg->num1 + $arg->num2;
}

say add_numbers( num1 => 5, num2 => 10 );      # says 15
say add_numbers( { num1 => 5, num2 => 10 } );  # also says 15
say add_numbers( 5, num2 => 10 );              # says 15 yet again
say add_numbers( 5, { num2 => 10 } );          # guess what? says 15
say add_numbers( 10, num1 => 5 );              # 14. just kidding! 15
say add_numbers( 10, { num1 => 5 } );          # another 15
say add_numbers( 5, 10 );                      # surprise, it says 15

# BAD: list_to_named argument cannot be at the end.
say add_numbers( { num1 => 5 }, 10 );

# BAD: list_to_named argument duplicated.
say add_numbers( 5, 10, { num1 => 5 } );

okay so where a hash or hashref of named parameters are expected, any parameter which doesn't look like it fits that pattern will be treated as a "sneaky" positional parameter, and will be tried the first time a named parameter seems to be missing. ๐Ÿ™ˆ

This feature is normally only applied to required parameters. It can be manually controlled on a per-parameter basis using the in_list option. ๐Ÿ’…

Type::Params attempts to be intelligent at figuring out what order the sneaky positional parameters were given in. โœจ

        signature_for add_to_ref => (
          named         => [ ref => ScalarRef[Num], add => Num ],
          list_to_named => true,
        );

        sub add_to_ref ( $arg ) {
          $arg->ref->$* += $arg->num;
        }

        my $sum = 0;
        add_to_ref( ref => \$sum, add => 1 );
        add_to_ref( \$sum, add => 2 );
        add_to_ref( \$sum, 3 );
        add_to_ref( 4, \$sum );
        add_to_ref( 5, sum => \$sum );
        add_to_ref( add => 5, sum => \$sum );
        say $sum; # 21

This approach is somewhat slower, but has the potential for very do-what-I-mean functions. ๐Ÿฆ‹

Note that list_to_named and named_to_list can both be used in the same signature as their meanings are not contradictory. ๐Ÿ’–

        signature_for add_to_ref => (
          named         => [ ref => ScalarRef[Num], add => Num ],
          list_to_named => true,
          named_to_list => true,
        );

        sub add_to_ref ( $ref, $num ) {
          $ref->$* += $num;
        }

head โ€” Int|ArrayRef ๐Ÿ‘‘

head provides an additional list of non-optional, positional parameters at the start of @_. This is often used for method calls. For example, if you wish to define a signature for:

        $object->my_method( foo => 123, bar => 456 );

You could write it as this:

        signature_for my_method => (
          head    => [ Object ],
          named   => [ foo => Optional[Int], bar => Optional[Int] ],
        );

        sub my_method ( $self, $arg ) {
          ...;
        }

If head is set as a number instead of an arrayref, it is the number of additional arguments at the start:

        signature_for stash_foobar = (
          head    => 2,
          named   => [ foo => Optional[Int], bar => Optional[Int] ],
        );

        sub stash_foobar ( $self, $ctx, $arg ) {
          $ctx->stash->{foo} = $arg->foo if $arg->has_foo;
          $ctx->stash->{bar} = $arg->bar if $arg->has_bar;
          return $self;
        }

        ...;

        $app->stash_foobar( $context, foo => 123 );

In this case, no type checking is performed on those additional arguments; it is just checked that they exist. ๐Ÿ‘€

tail โ€” Int|ArrayRef ๐ŸŽ€

A tail is like a head except that it is for arguments at the end of @_.

        signature_for my_method => (
          head    => [ Object ],
          named   => [ foo => Optional[Int], bar => Optional[Int] ],
          tail    => [ CodeRef ],
        );

        sub my_method ( $self, $arg, $callback ) {
          ...;
        }

        $object->my_method( foo => 123, bar => 456, sub { ... } );

method โ€” Bool|TypeTiny ๐Ÿซถ

While head can be used for method signatures, a more declarative way is to set method => true.

If you wish to be specific that this is an object method, intended to be called on blessed objects only, then you may use method => Object, using the Object type from Types::Standard. If you wish to specify that it's a class method, then use method => Str, using the Str type from Types::Standard. (method => ClassName is perhaps clearer, but it's a slower check.)

        signature_for my_method => (
          method  => true,
          named   => [ foo => Optional[Int], bar => Optional[Int] ],
        );

        sub my_method ( $self, $arg ) {
          ...;
        }

The method option has some other subtle differences from head. Any parameter defaults which are coderefs will be called as methods on the invocant instead of being called with no arguments. The package option will be interpreted slightly differently.

It is possible to use both method and head in the same signature. The invocant is interpreted as being before the head.

A shortcut is provided for method => true, though it also enables a couple of other options.

        use Type::Params qw( signature_for_method );

        signature_for_method my_method => (
          named => [ foo => Optional[Int], bar => Optional[Int] ],
        );

        sub my_method ( $self, $arg ) {
          ...;
        }

description โ€” Str ๐Ÿ“

This is the description of the coderef that will show up in stack traces. It defaults to parameter validation for X where X is the sub name. Usually the default will be fine.

package โ€” Str ๐Ÿ“ฆ

This allows you to add signatures to functions in other packages:

        signature_for foo => ( package => "Some::Package", ... );

If method is true and Some::Package doesn't contain a sub called foo, then Type::Params will traverse the inheritance heirarchy, looking for foo.

If any type constraints are specified as strings, Type::Params will look for types imported by this package.

        # Expects the MyInt type to be known by Some::Package.
        signature_for foo => ( package => "Some::Package", pos => [ 'MyInt' ] );

This is also supported:

        signature_for "Some::Package::foo" => ( ... );

fallback โ€” CodeRef|Bool ๐Ÿ“

If the sub being wrapped cannot be found, then signature_for will usually throw an error. If you want it to "still work" in this situation, use the fallback option. fallback => \&alternative_coderef_to_wrap will instead wrap a different coderef if the original cannot be found. fallback => true is a shortcut for fallback => sub {}. An example where this might be useful is if you're adding signatures to methods which are inherited from a parent class, but you are not 100% confident will exist (perhaps dependent on the version of the parent class).

        signature_for add_nums => (
          positional => [ Num, Num ],
          fallback   => sub { $_[0] + $_[1] },
        );

on_die โ€” Maybe[CodeRef] ๐Ÿ’€

Usually when the signature check hits an error, it will throw an exception, which is a blessed Error::TypeTiny object.

If you provide an on_die coderef, then instead the Error::TypeTiny object will be passed to it.

        signature_for add_numbers => (
          positional => [ Num, Num ],
          on_die     => sub {
            my $error = shift;
            print "Existential crisis: $error\n";
            exit( 1 );
          },
        );

        sub add_numbers ( $num1, $num2 ) {
          return $num1 + $num2;
        }

        say add_numbers();   # has an existential crisis

If your on_die coderef doesn't exit or throw an exception, it can instead return a list which will be used as parameters for your function.

        signature_for add_numbers => (
          positional => [ Num, Num ],
          on_die     => sub { return ( 40, 2 ) },
        );

        sub add_numbers ( $num1, $num2 ) {
          return $num1 + $num2;
        }

        say add_numbers();   # 42

This is probably not very useful. ๐Ÿ˜ญ

strictness โ€” Bool|Str ๐Ÿ”ฅ

If you set strictness to false, then certain signature checks will simply never be done. The initial check that there's the correct number of parameters, plus type checks on parameters which don't coerce can be skipped.

If you set it to true or do not set it at all, then these checks will always be done.

Alternatively, it may be set to the quoted fully-qualified name of a Perl global variable or a constant, and that will be compiled into the coderef as a condition to enable strict checks.

        signature_for my_func => (
          strictness => '$::CHECK_TYPES',
          positional => [ Int, ArrayRef ],
        );

        sub my_func ( $int, $aref ) {
          ...;
        }

        # Type checks are skipped
        {
          local $::CHECK_TYPES = false;
          my ( $number, $list ) = my_func( {}, {} );
        }

        # Type checks are performed
        {
          local $::CHECK_TYPES = true;
          my ( $number, $list ) = my_func( {}, {} );
        }

A recommended use of strictness is with Devel::StrictMode.

        use Devel::StrictMode qw( STRICT );

        state $signature = signature(
          strictness => STRICT,
          positional => [ Int, ArrayRef ],
        );

multiple โ€” ArrayRef|HashRef ๐ŸŒˆ

This option allows your signature to support multiple calling conventions. Each entry in the array is an alternative signature, as a hashref:

        signature_for my_func => (
          multiple => [
            {
              positional    => [ ArrayRef, Int ],
            },
            {
              named         => [ array => ArrayRef, index => Int ],
              named_to_list => true,
            },
          ],
        );

        sub my_func ( $aref, $int ) {
          ...;
        }

That signature will allow your function to be called as:

        your_function( $arr, $ix );
        your_function( array => $arr, index => $ix );
        your_function( { array => $arr, index => $ix } );

Sometimes the alternatives will return the parameters in different orders:

        signature_for my_func => (
          multiple => [
            { positional => [ ArrayRef, Int ] },
            { positional => [ Int, ArrayRef ] },
          ],
        );

So how does your sub know how it's been called? One option is to use the ${^_TYPE_PARAMS_MULTISIG} global variable which will be set to the index of the signature which was used:

        sub my_func {
          my ( $arr, $ix ) = ${^_TYPE_PARAMS_MULTISIG} == 1 ? reverse( @_ ) : @_;
          ...;
        }

If you'd prefer to use identifying names instead of a numeric index, you can specify these using ID:

        signature_for my_func => (
          multiple => [
            { ID => 'one', positional => [ ArrayRef, Int ] },
            { ID => 'two', positional => [ Int, ArrayRef ] },
          ],
        );

Or by using a hashref:

        signature_for my_func => (
          multiple => {
            one => { positional => [ ArrayRef, Int ] },
            two => { positional => [ Int, ArrayRef ] },
          },
        );

A neater solution is to use a next coderef to re-order alternative signature results into your preferred order:

        signature_for my_func => (
          multiple => [
            { positional => [ ArrayRef, Int ] },
            { positional => [ Int, ArrayRef ], next => sub { reverse @_ } },
          ],
        );

        sub my_func ( $arr, $ix ) {
          ...;
        }

While conceptually multiple is an arrayref of hashrefs, it is also possible to use arrayrefs in the arrayref.

        multiple => [
          [ ArrayRef, Int ],
          [ Int, ArrayRef ],
        ]

When an arrayref is used like that, it is a shortcut for a positional signature.

Coderefs may additionally be used:

        signature_for my_func => (
          multiple => [
            [ ArrayRef, Int ],
            { positional => [ Int, ArrayRef ], next => sub { reverse @_ } },
            sub { ... },
            sub { ... },
          ],
        );

Okay so those coderefs? They need to be subs that return a list of params when everything goes right, and throw an exception when it doesn't. That's the whole deal.

These two signatures are literally the same thing, bestie:

signature_for my_func => (
  multiple => [
    { method => true, positional => [ ArrayRef, Int ] },
    { method => true, positional => [ Int, ArrayRef ] },
  ],
);

signature_for my_func => (
  method   => true,
  multiple => [
    { positional => [ ArrayRef, Int ] },
    { positional => [ Int, ArrayRef ] },
  ],
);

Also you can shorten multiple to multi (fr fr) โ€” so signature( multi => [...] ) does the exact same job as signature( multiple => [...] ). Three whole keystrokes saved! ๐Ÿ’…

Heads up from the archive: in older releases of Type::Params, ${^_TYPE_PARAMS_MULTISIG} was called ${^TYPE_PARAMS_MULTISIG}. That old name is not supported anymore, so don't come for her.

๐ŸŒŸ message Str ๐ŸŒŸ

Only multiple signatures care about this one. It's the error message that gets thrown when none of your signatures match.

๐Ÿ’– bless Bool|ClassName, class ClassName|ArrayRef, and constructor Str ๐Ÿ’–

Named params usually come back as a blessed object:

signature_for add_numbers => ( named => [ num1 => Num, num2 => Num ] );

sub add_numbers ( $arg ) {
  return $arg->num1 + $arg->num2;
}

The class they get blessed into is one that Type::Params builds on the fly. But these three options let you take the wheel. ๐Ÿš—

First up: if you set bless => false and leave class and constructor unset, then $arg is just a plain unblessed hashref.

signature_for add_numbers => (
  named        => [ num1 => Num, num2 => Num ],
  bless        => false,
);

sub add_numbers ( $arg ) {
  return $arg->{num1} + $arg->{num2};
}

That's a nice little speed boost, but ngl having proper methods for each named param is a genuinely helpful way to catch misspelled names. ๐Ÿ‘‘

If you'd rather hand-make a class instead of letting Type::Params generate one on the fly, go off:

package Params::For::AddNumbers {
  sub num1 ( $self ) {
    return $self->{num1};
  }
  sub num2 ( $self ) {
    return $self->{num2};
  }
  sub sum ( $self ) {
    return $self->num1 + $self->num2;
  }
}

signature_for add_numbers => (
  named        => [ num1 => Num, num2 => Num ],
  bless        => 'Params::For::AddNumbers',
);

sub add_numbers ( $arg ) {
  return $arg->sum;
}

Note that Params::For::AddNumbers up there has no new method, because Type::Params is just gonna do bless( $arg, $opts{bless} ) directly. No constructor required, periodt.

If you do want a real constructor involved, use the class option instead:

package Params::For::AddNumbers {
  use Moo;
  has [ 'num1', 'num2' ] => ( is => 'ro' );
  sub sum {
    my $self = shift;
    return $self->num1 + $self->num2;
  }
}

signature_for add_numbers => (
  named        => [ num1 => Num, num2 => Num ],
  class        => 'Params::For::AddNumbers',
);

sub add_numbers ( $arg ) {
  return $arg->sum;
}

And if your constructor is named something other than new, do this:

signature_for add_numbers => (
  named        => [ num1 => Num, num2 => Num ],
  class        => 'Params::For::AddNumbers',
  constructor  => 'new_from_hashref',
);

Or the shortcut version:

signature_for add_numbers => (
  named        => [ num1 => Num, num2 => Num ],
  class        => [ 'Params::For::AddNumbers' => 'new_from_hashref' ],
);

Honestly? It is doubtful you want any of these options, except bless => false. Just saying. ๐Ÿซถ

โญ returns TypeTiny, returns_scalar TypeTiny, and returns_list TypeTiny โญ

These let you declare the type your function gives back.

signature_for round_number => (
  pos          => [ Num ],
  returns      => Int,
);

sub round_number ( $num ) {
  return int( $num );
}

If your function returns different types in scalar context vs list context, returns_scalar and returns_list let you indicate separate return types for each context:

signature_for my_func => (
  pos             => [ Int, Int ],
  returns_scalar  => Int,
  returns_list    => Tuple[ Int, Int, Int ],
);

The returns_list constraint gets defined using an ArrayRef-like or HashRef-like type constraint, even though it's returning a list and not a single reference. Yeah, it's giving "why tho", but that's the vibe.

If your function is called in void context, its return value is unimportant and shouldn't be type checked. Period. ๐Ÿ’…

๐Ÿฆ‹ allow_dash Bool ๐Ÿฆ‹

For any "word-like" named params or aliases, this automatically creates an alias with a leading hyphen:

signature_for withdraw_funds => (
  named      => [ amount => Num, account => Str ],
  allow_dash => true,
);

sub withdraw_funds ( $arg ) {
  ...;
}

withdraw_funds(  amount => 11.99,  account => 'ABC123' );
withdraw_funds( -amount => 11.99,  account => 'ABC123' );
withdraw_funds(  amount => 11.99, -account => 'ABC123' );
withdraw_funds( -amount => 11.99, -account => 'ABC123' );

Does absolutely nothing for names that aren't word-like. Word-like names = the ones matching /\A[^\W0-9]\w*\z/ โ€” essentially anything Perl lets you use as a normal unqualified variable name. iykyk.


๐ŸŒธ Parameter Options ๐ŸŒธ

In the parameter lists for the positional and named signature options, each param can be followed by a hashref of options that apply just to that one param:

signature_for my_func => (
  positional => [
    Int, \%options_for_first_parameter,
    Int, \%options_for_other_parameter,
  ],
  %more_options_for_signature,
);

signature_for my_func => (
  named => [
    foo => Int, \%options_for_foo,
    bar => Int, \%options_for_bar,
  ],
  %more_options_for_signature,
);

Here's everything that's supported for params. ๐Ÿ‘‡

๐ŸŽ€ optional Bool ๐ŸŽ€

An option called optional! (yes, that's the joke, moving on)

It makes a param optional:

signature_for add_nums => (
  positional => [
    Int,
    Int,
    Bool, { optional => true },
  ],
);

sub add_nums ( $num1, $num2, $debug ) {
  my $sum = $num1 + $num2;
  warn "$sum = $num1 + $num2" if $debug;
  return $sum;
}

add_nums( 2, 3, 1 );   # prints warning
add_nums( 2, 3, 0 );   # no warning
add_nums( 2, 3    );   # no warning

Types::Standard also provides an Optional parameterizable type which may be a neater way to do the same thing:

signature_for add_nums => ( pos => [ Int, Int, Optional[Bool] ] );

In signatures with positional params, any optional params must be defined after the non-optional ones. The tail option is the workaround if you need required params at the end of @_.

In signatures with named params, the order of optional and non-optional params is unimportant. Slay. โœจ

๐Ÿ’œ slurpy Bool ๐Ÿ’œ

A signature may contain a single slurpy param, and it mops up any other arguments the caller provides your function. ๐Ÿงน

In signatures with positional params, slurpy params must always have some kind of ArrayRef or HashRef type constraint, must always appear at the end of the list of positional params, and they work like this:

signature_for add_nums => (
  positional => [
    Num,
    ArrayRef[Num], { slurpy => true },
  ],
);

sub add_nums ( $first_num, $other_nums ) {
  my $sum = $first_num;
  for my $other ( $other_nums->@* ) {
    $sum += $other;
  }
  return $sum;
}

say add_nums( 1 );            # says 1
say add_nums( 1, 2 );         # says 3
say add_nums( 1, 2, 3 );      # says 6
say add_nums( 1, 2, 3, 4 );   # says 10

In signatures with named params, slurpy params must always have some kind of HashRef type constraint, and they work like this:

use builtin qw( true false );

signature_for process_data => (
  method => true,
  named  => [
    input   => FileHandle,
    output  => FileHandle,
    flags   => HashRef[Bool], { slurpy => true },
  ],
);

sub process_data ( $self, $arg ) {
  warn "Beginning data processing" if $arg->flags->{debug};
  ...;
}

$widget->process_data(
  input  => \*STDIN,
  output => \*STDOUT,
  debug  => true,
);

The Slurpy type constraint from Types::Standard may be used as a shortcut to specify slurpy params:

signature_for add_nums => (
  positional => [ Num, Slurpy[ ArrayRef[Num] ] ],
)

The type Slurpy[Any] is handled specially โ€” it's treated as a slurpy ArrayRef in signatures with positional params, and a slurpy HashRef in signatures with named params, but it has some additional optimizations for speed. ๐Ÿ”ฅ

๐Ÿ“ default CodeRef|ScalarRef|Ref|Str|Undef ๐Ÿ“

A default may be provided for a param:

signature_for my_func => (
  positional => [
    Int,
    Int, { default => "666" },
    Int, { default => "999" },
  ],
);

Supported defaults are any strings (numerical ones included), undef, and empty hashrefs and arrayrefs. Non-empty hashrefs and arrayrefs are not allowed as defaults.

Alternatively, you may provide a coderef to generate a default value:

signature_for my_func => (
  positional => [
    Int,
    Int, { default => sub { 6 * 111 } },
    Int, { default => sub { 9 * 111 } },
  ]
);

That coderef may generate literally any value, including non-empty arrayrefs and non-empty hashrefs. But for undef, simple strings, numbers, and empty structures, avoiding a coderef will make your parameter processing faster.

Instead of a coderef, you can use a reference to a string of Perl source code:

signature_for my_func => (
  positional => [
    Int,
    Int, { default => \ '6 * 111' },
    Int, { default => \ '9 * 111' },
  ],
);

Defaults will be validated against the type constraint, and potentially coerced.

Any param with a default will automatically be optional, as it makes no sense to provide a default for required parameters. ๐Ÿ™ˆ

Bestie, be warned: having any defaults in a signature (even if they never end up getting used) can slow it down, because Type::Params will need to build a new array instead of just returning @_.

๐ŸŒˆ default_on_undef Bool ๐ŸŒˆ

Normally defaults are only applied when a param is missing (think exists for hashes, or the array being too short). Setting default_on_undef to true will also trigger the default if a param is provided but undefined.

If the caller might legitimately want to supply undef as a value, it is not recommended you use this.

coerce Bool

Okay so now that we're talking coercion โ€” the coerce option is literally just you saying "yes bestie, pls turn this value into the right type for me":

signature_for my_func => (
  positional => [
    Int,
    Int,
    Bool, { coerce => true },
  ],
);

Set coerce to false and coercion is off. No coercion for you. ๐Ÿ’…

If coerce isn't specified at all โ€” so it's neither true nor false โ€” then coercion gets switched on whenever the type constraint actually has a coercion, and switched off when it doesn't. So it's like, vibes-based, but in a documented way.

Heads up though: having any coercions in a signature (even ones that never end up getting used, like, ever) can slow it down, because Type::Params has to build a whole new array instead of just handing you back @_. Not me making the performance girlies cry ๐Ÿ˜ญ

clone Bool

Set this to true and it will deep clone incoming values via dclone from Storable (a core module since Perl 5.7.3, so it's giving very much available).

In the example below, $arr is a reference to a clone of @numbers, so pushing extra numbers onto it leaves @numbers completely unbothered:

signature_for foo => (
  positional => [ ArrayRef, { clone => true } ],
);

sub foo ( $arr ) {
  push @$arr, 4, 5, 6;
}

my @numbers = ( 1, 2, 3 );
foo( \@numbers );
print "@numbers\n";  ## 1 2 3
But bestie, note that cloning will significantly slow down your signature. That's the tradeoff, no cap.

name Str

This overrides the name of a named parameter. And honestly? I don't know why you would want to do that. ๐Ÿ™ˆ

The following signature has two parameters: foo and bar. The name fool is completely ignored. Like, it's not even in the group chat.

signature_for my_func => (
  named => [
    fool   => Int, { name => 'foo' },
    bar    => Int,
  ],
);

You can, however, also name positional parameters, which don't usually have names at all:

signature_for my_func => (
  positional => [
    Int, { name => 'foo' },
    Int, { name => 'bar' },
  ],
);

The names of positional parameters are not really used for anything at the moment, but may be incorporated into error messages or similar in the future. So they're just sitting there, being cute, waiting for their moment. โœจ

getter Str

For signatures with named parameters, this specifies the method name used to retrieve this parameter's value from the $arg object:

signature_for process_data => (
  method => true,
  named  => [
    input   => FileHandle,    { getter => 'in' },
    output  => FileHandle,    { getter => 'out' },
    flags   => HashRef[Bool], { slurpy => true },
  ],
);

sub process_data ( $self, $arg ) {
  warn "Beginning data processing" if $arg->flags->{debug};

  my ( $in, $out ) = ( $arg->in, $arg->out );
  ...;
}

$widget->process_data(
  input  => \*STDIN,
  output => \*STDOUT,
  debug  => true,
);

Ignored by signatures with positional parameters. They simply do not care. ๐Ÿ’€

predicate Str

The $arg object that named-parameter signatures hand you will also include has methods for any optional arguments. Obsessed. For example:

signature_for process_data => (
  method => true,
  named  => [
    input   => Optional[ FileHandle ],
    output  => Optional[ FileHandle ],
    flags   => Slurpy[ HashRef[Bool] ],
  ],
);

sub process_data ( $self, $arg ) {

  if ( $self->has_input and $self->has_output ) {
    ...;
  }

  ...;
}

Setting a predicate option lets you pick a totally different name for this method instead of the default has_* situation.

It is also possible to set a predicate for non-optional parameters, which don't normally get a has method at all. So they get to have one, as a treat. ๐ŸŽ€

Ignored by signatures with positional parameters.

alias Str|ArrayRef[Str]

A list of alternative names for the parameter, or a single alternative name. It's giving "go by many names, main character energy":

signature_for add_numbers => (
  named => [
    first_number   => Int, { alias => [ 'x' ] },
    second_number  => Int, { alias =>   'y'   },
  ],
);

sub add_numbers ( $arg ) {
  return $arg->first_number + $arg->second_number;
}

say add_numbers( first_number => 40, second_number => 2 );  # 42
say add_numbers( x            => 40, y             => 2 );  # 42
say add_numbers( first_number => 40, y             => 2 );  # 42
say add_numbers( first_number => 40, x => 1, y => 2 );      # dies!

That last one dies โ€” you cannot pass the same parameter twice under two different aliases, so don't try it. ๐Ÿ˜ญ

Ignored by signatures with positional parameters.

in_list Bool

In conjunction with list_to_named, this determines if this parameter can be provided as part of the list of "sneaky" positional parameters. If list_to_named isn't being used, in_list is ignored. Straight up ghosted.

Defaults to false if the parameter is optional or has a default. Defaults to true if the parameter is required.

strictness Bool|Str

Overrides the signature option strictness on a per-parameter basis. Yes, per-parameter. Very granular of it. ๐Ÿ’…


signature_for_func $function_name => ( %spec )

Like signature_for and defaults to method => false.

If the signature has named parameters, it will additionally default list_to_named and allow_dash to true.

signature_for_func add_to_ref => (
  named         => [ ref => ScalarRef[Num], add => Num ],
  named_to_list => true,
);

sub add_to_ref ( $ref, $add ) {
  $ref->$* += $add;
}

my $sum = 0;
add_to_ref( ref => \$sum, add => 1 );
add_to_ref( \$sum, 2 );
add_to_ref( 3, \$sum );
add_to_ref( 4, { -ref => \$sum } );
say $sum; # 10
The exact behaviour of signature_for_func is unstable and may change in future versions of Type::Params. So like, don't build your whole personality around it, bestie.

signature_for_method $function_name => ( %spec )

Like signature_for but will default method => true.

If the signature has named parameters, it will additionally default list_to_named and allow_dash to true.

package Calculator {
  use Types::Standard qw( Num ScalarRef );
  use Type::Params qw( signature_for_method );

  ...;

  signature_for_method add_to_ref => (
    named         => [ ref => ScalarRef[Num], add => Num ],
    named_to_list => true,
  );

  sub add_to_ref ( $self, $ref, $add ) {
    $ref->$* += $add;
  }
}

my $calc = Calculator->new;
my $sum = 0;
$calc->add_to_ref( ref => \$sum, add => 1 );
$calc->add_to_ref( \$sum, 2 );
$calc->add_to_ref( 3, \$sum );
$calc->add_to_ref( 4, { -ref => \$sum } );
say $sum; # 10
The exact behaviour of signature_for_method is also unstable and may change in future versions of Type::Params. Same warning, same energy. ๐Ÿซถ

signature( %spec )

The signature function allows more fine-grained control over signatures. Instead of automatically wrapping your function, it returns a coderef that you can pass @_ to. It's like, you get the keys to the car instead of being driven around. ๐Ÿš—โœจ

The following are roughly equivalent:

signature_for add_nums => ( pos => [ Num, Num ] );

sub add_nums ( $x, $y ) {
  return $x + $y;
}

And:

sub add_nums {
  state $signature = signature( pos => [ Num, Num ] );
  my ( $x, $y ) = $signature->( @_ );

  return $x + $y;
}

Perl allows a slightly archaic way of calling coderefs without using parentheses, which may be slightly faster at the cost of being more obscure:

sub add_nums {
  state $signature = signature( pos => [ Num, Num ] );
  my ( $x, $y ) = &$signature; # important: no parentheses!

  return $x + $y;
}

If you need to support Perl 5.8, which didn't have the state keyword (aw, bless, a historical artefact ๐Ÿ’€):

my $__add_nums_sig;
sub add_nums {
  $__add_nums_sig ||= signature( pos => [ Num, Num ] );
  my ( $x, $y ) = &$__add_nums_sig;

  ...;
}

This gives you more control over how and when the signature is built and used, and what is done with the values it unpacks.

In particular, note that if your function is never called, the signature never even gets built, meaning that for functions you rarely use, there's less cost to having the signature. Lazy loading, but make it signatures. โœจ

As of 2025, you probably want to be using signature_for instead of signature in most cases.

Additional Signature Specification Options

There are certain options which make no sense for signature_for, and are only useful for signature. Others may behave slightly differently. These are noted here.

returns TypeTiny, returns_scalar TypeTiny, and returns_list TypeTiny

Because signature isn't capable of fully wrapping your function, the returns, returns_scalar, and returns_list options cannot do anything. You should consider them to be documentation only. They're decorative. Ornamental. Just there for the lore. ๐Ÿ’…

subname Str

The name of the sub whose parameters we're supposed to be checking. This is useful in stack traces, etc. Defaults to the caller.

package Str

Works the same as in signature_for, but it's worth mentioning it again as it ties in closely with subname.

caller_level Int

If you're wrapping signature so that you can check signatures on behalf of another package, then setting caller_level to 1 (or more, depending on the level of wrapping!) may be an alternative to manually setting the package and subname.

next Bool|CodeLike

This can be used for chaining coderefs. If you understand on_die, this acts like an on_live. Iconic symmetry, honestly.

sub add_numbers {
  state $sig = signature(
    positional => [ Num, Num ],
    next => sub {
      my ( $num1, $num2 ) = @_;

      return $num1 + $num2;
    },
  );

  my $sum = $sig->( @_ );
  return $sum;
}

say add_numbers( 2, 3 );   # says 5

If set to true instead of a coderef, has a slightly different behaviour:

sub add_numbers {
  state $sig = signature(
    positional => [ Num, Num ],
    next       => true,
  );

  my $sum = $sig->(
    sub { return $_[0] + $_[1] },
    @_,
  );
  return $sum;
}

say add_numbers( 2, 3 );   # says 5

This looks strange. Why would this be useful? Well, it works nicely with Moose's around keyword.

sub add_numbers {
  return $_[1] + $_[2];
}

around add_numbers => signature(
  method     => true,
  positional => [ Num, Num ],
  next       => true,
  package    => __PACKAGE__,
  subname    => 'add_numbers',
);

say __PACKAGE__->add_numbers( 2, 3 );   # says 5

Note the way around works in Moose is that it expects a wrapper coderef as its final argument. That wrapper coderef then expects to be given a reference to the original function as its first parameter.

This can allow, for example, a role to provide a signature wrapping a method defined in a class.

This is kind of complex, and you're unlikely to use it, but it's been proven useful for tools that integrate Type::Params with Moose-like method modifiers. So like, niche but slay. ๐Ÿ”ฅ

Note that next is the mechanism that signature_for internally uses to connect the signature with the wrapped sub, so using next with signature_for is a good recipe for headaches. Like, migraines. Don't do it. ๐Ÿ˜ญ

Okay so if you're using multiple signatures, next is your bestie for each inner signature โ€” it massages the params into the correct order. This use of next is supported for signature_for. โœจ

The option goto_next is supported as a historical alias for next. iykyk ๐Ÿ’…

  • want_source Bool โ€” Instead of returning a coderef, return Perl source code string. Handy for debugging. ๐Ÿ›
  • want_details Bool โ€” Instead of returning a coderef, return a hashref of stuff including the coderef. This is mostly for people extending Type::Params and ngl I won't go into too many details about what else this hashref contains. ๐Ÿ™ˆ
  • want_object Bool โ€” Instead of returning a coderef, return a Type::Params::Signature object. This is the more modern version of want_details. ๐Ÿ‘‘

๐Ÿง“ LEGACY API ๐Ÿง“

The following functions were the API prior to Type::Params v2. They are still supported, but their use is now discouraged. ๐Ÿ˜ญ

If you don't provide an import list at all, you will import compile and compile_named:

 use Type::Params;

This does the same:

  use Type::Params -v1;

The following exports compile, compile_named, and compile_named_oo:

 use Type::Params -compile;

The following exports wrap_subs and wrap_methods:

 use Type::Params -wrap;

compile( @pos_params )

Equivalent to signature( positional => \@pos_params ).

compile( \%spec, @pos_params ) is equivalent to signature( %spec, positional => \@pos_params ).

compile_named( @named_params )

Equivalent to signature( bless => 0, named => \@named_params ).

compile_named( \%spec, @named_params ) is equivalent to signature( bless => false, %spec, named => \@named_params ).

compile_named_oo( @named_params )

Equivalent to signature( bless => true, named => \@named_params ).

compile_named_oo( \%spec, @named_params ) is equivalent to signature( bless => true, %spec, named => \@named_params ).

validate( \@args, @pos_params )

Equivalent to signature( positional => \@pos_params )->( @args ).

The validate function has never been recommended, and is not exported unless requested by name. ๐Ÿ’€

validate_named( \@args, @named_params )

Equivalent to signature( bless => false, named => \@named_params )->( @args ).

The validate_named function has never been recommended, and is not exported unless requested by name. ๐Ÿ’€

wrap_subs( func1 => \@params1, func2 => \@params2, ... )

Equivalent to:

 signature_for func1 => ( positional => \@params1 );
 signature_for func2 => ( positional => \@params2 );

One slight difference is that instead of arrayrefs, you can provide the output of one of the compile functions:

 wrap_subs( func1 => compile_named( @params1 ) );

wrap_subs is not exported unless requested by name. ๐Ÿซฃ

wrap_methods( func1 => \@params1, func2 => \@params2, ... )

Equivalent to:

 signature_for func1 => ( method => 1, positional => \@params1 );
 signature_for func2 => ( method => 1, positional => \@params2 );

One slight difference is that instead of arrayrefs, you can provide the output of one of the compile functions:

 wrap_methods( func1 => compile_named( @params1 ) );

wrap_methods is not exported unless requested by name. ๐Ÿซฃ

multisig( @alternatives )

Equivalent to:

 signature( multiple => \@alternatives )

multisig( \%spec, @alternatives ) is equivalent to signature( %spec, multiple => \@alternatives ).


๐Ÿงฌ TYPE CONSTRAINTS ๐Ÿงฌ

Although Type::Params is not a real type library, it exports two type constraints. Their use is no longer recommended. ๐Ÿ˜ฌ

Invocant

Type::Params exports a type Invocant on request. This gives you a type constraint which accepts classnames and blessed objects. ๐ŸŽ€

 use Type::Params qw( compile Invocant );

 signature_for my_method => (
   method     => Invocant,
   positional => [ ArrayRef, Int ],
 );

 sub my_method ($self_or_class, $arr, $ix) {
   return $arr->[ $ix ];
 }

Invocant is not exported unless requested by name.

Recommendation: use Defined from Types::Standard instead. ๐Ÿ’ก

ArgsObject

Type::Params exports a parameterizable type constraint ArgsObject. It accepts the kinds of objects returned by signature checks for named parameters. ๐Ÿฆ‹

  use v5.36;

  package Foo {
    use Moo;
    use Type::Params 'ArgsObject';

    has args => (
      is  => 'ro',
      isa => ArgsObject['Bar::bar'],
    );
  }

  package Bar {
    use Types::Standard -types;
    use Type::Params 'signature_for';

    signature_for bar => ( named => [ xxx => Int, yyy => ArrayRef ] );

    sub bar ( $got ) {
      return 'Foo'->new( args => $got );
    }
  }

  Bar::bar( xxx => 42, yyy => [] );

The parameter Bar::bar refers to the caller when the check is compiled, rather than when the parameters are checked.

ArgsObject is not exported unless requested by name.

Recommendation: use Object from Types::Standard instead. ๐Ÿ’ก


๐Ÿ”’ CONSTANTS ๐Ÿ”’

The constants SIGNATURE_SUBNAME_PREFIX and SIGNATURE_SUBNAME_SUFFIX exist. They normally return the empty string, but can be influenced by environment variables. (See below.) They are not exportable. ๐Ÿšซ


๐ŸŒ ENVIRONMENT ๐ŸŒ

PERL_TYPE_PARAMS_XS

Affects the building of accessors for $arg objects. If set to true, will use Class::XSAccessor. If set to false, will use pure Perl. If this environment variable does not exist, will use Class::XSAccessor. ๐Ÿงช

If Class::XSAccessor is not installed or is too old, pure Perl will always be used as a fallback. ๐Ÿ›Ÿ

PERL_TYPE_PARAMS_SUBNAME_PREFIX and PERL_TYPE_PARAMS_SUBNAME_SUFFIX

Every Perl subroutine has an idea of its fully-qualified subname, which is distinct from how it is actually called. For example:

 package Foo;
 *bar = sub { return "foobar" };

The subroutine can be called as Foo::bar(), however the subroutine still "thinks" it is an anonymous coderef because that is how it was initially created. That is how it will show up in stack traces, profiling tools, etc. These names can be manipulated with Sub::Util. ๐Ÿ”

By default, if you use signature_for to define a signature for YourModule::yourfunc(), then the wrapper function it creates will also give itself the subname of YourModule::yourfunc(). This is normally helpful. ๐Ÿ˜Œ

However, if you are debugging or profiling and wish to give the wrapper subs a different subname in stack traces or profiling reports, these environment variables allow you to control that. They will have a global effect on your application. ๐ŸŒŽ

PERL_TYPE_PARAMS_SUBNAME_PREFIX can be set to true to tell Type::Params to add SIGNATURE_FOR:: to the start of the wrapper function's subname. Or it can be set to any string ending :: to specify an alternative prefix. ๐Ÿท๏ธ

PERL_TYPE_PARAMS_SUBNAME_SUFFIX can be set to true to tell Type::Params to add _SIGNATURE to the end of the wrapper function's subname. Or it can be set to any string starting _ to specify an alternative suffix. ๐Ÿท๏ธ

There's usually no reason to apply both a prefix and a suffix. ๐Ÿคท

Suffixes may play nicer with utilities like namespace::autoclean. ๐Ÿงผ

Example usage:

 export PERL_TYPE_PARAMS_SUBNAME_SUFFIX=1
 perl -d:NYTProf some_perl.pl

๐Ÿช HOOKS ๐Ÿช

You can install coderefs which will be called whenever signature_for, signature_for_func, or signature_for_method are used to wrap a function or method. They are ignored by signature and by the pre-v2 API. ๐Ÿ™…

  push @{ $Type::Params::POST_INSTALL{'My::Package'} ||= [] }, sub {
    my $signature = shift;
    ...;
  };

  push @{ $Type::Params::PRE_INSTALL{'My::Package'} ||= [] }, sub {
    my $signature = shift;
    ...;
  };

The $signature will be a blessed Type::Params::Signature object. ๐ŸŽ

The intention for this is to allow for future extensions to expose signature data as metadata. ๐Ÿ”ฎ


๐Ÿ› BUGS ๐Ÿ›

Please report any bugs to <https://github.com/tobyink/p5-type-tiny/issues>. ๐Ÿซถ


๐Ÿ‘€ SEE ALSO ๐Ÿ‘€

The Type::Tiny homepage <https://typetiny.toby.ink/>. ๐ŸŒˆ

Type::Tiny, Type::Coercion, Types::Standard.


โœ๏ธ AUTHOR โœ๏ธ

Toby Inkster <tobyink@cpan.org>. ๐Ÿ’–


This software is copyright (c) 2013-2014, 2017-2025 by Toby Inkster.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.


โš ๏ธ DISCLAIMER OF WARRANTIES โš ๏ธ

THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.


โœจ That's the whole page, bestie! This tea was poured from perl v5.42.0, dated 2026-01-17, and it's literally Type::Params(3). Now go slay those signatures. ๐Ÿ’…๐Ÿ’–

๐Ÿ“ฆ where this page comes from