NAME
Function::Parameters - subroutine definitions with parameter lists
SYNOPSIS
use Function::Parameters qw(:strict);
# simple function
fun foo($bar, $baz) {
return $bar + $baz;
}
# function with prototype
fun mymap($fun, @args)
:(&@)
{
my @res;
for (@args) {
push @res, $fun->($_);
}
@res
}
print "$_\n" for mymap { $_ * 2 } 1 .. 4;
# method with implicit $self
method set_name($name) {
$self->{name} = $name;
}
# method with explicit invocant
method new($class: %init) {
return bless { %init }, $class;
}
# function with optional parameters
fun search($haystack, $needle = qr/^(?!)/, $offset = 0) {
...
}
# method with named parameters
method resize(:$width, :$height) {
$self->{width} = $width;
$self->{height} = $height;
}
$obj->resize(height => 4, width => 5);
# function with named optional parameters
fun search($haystack, :$needle = qr/^(?!)/, :$offset = 0) {
...
}
my $results = search $text, offset => 200;
DESCRIPTION
This module extends Perl with keywords that let you define functions with parameter lists. It uses Perl's keyword plugin API, so it works reliably and doesn't require a source filter.
Basics
The anatomy of a function (as recognized by this module):
The keyword introducing the function.
The function name (optional).
The parameter list (optional).
The prototype (optional).
The attribute list (optional).
The function body.
Example:
# (1) (2) (3) (4) (5) (6)
fun foo ($x, $y) :($$) :lvalue { ... }
# (1) (6)
my $f = fun { ... };
In the following section I'm going to describe all parts in order from simplest to most complex.
Body
This is just a normal block of statements, as with sub
. No surprises here, except the function name (along with its prototype, if any) is already in scope in its body. This is not the case with sub
:
sub foo ($$) {
# foo 1, 2; # a syntax error: 'foo' is not known to be a function yet
foo(42); # OK: calls 'foo' with one argument despite prototype
}
On the other hand:
use Function::Parameters;
fun foo :prototype($$) {
foo 1, 2; # OK: 'foo' and its prototype are in scope
# foo(42); # error: Not enough arguments for main::foo at X line Y, near "42)"
}
Name
If present, it specifies the name of the function being defined. As with sub
, if a name is present, by default the whole declaration is syntactically a statement and its effects are performed at compile time (i.e. at runtime you can call functions whose definitions only occur later in the file - but see the runtime
flag below). If no name is present, the declaration is an expression that evaluates to a reference to the function in question.
Attributes
Attributes are relatively unusual in Perl code, but if you want them, they work exactly the same as with sub
.
Prototype
As with sub
, a prototype, if present, contains hints as to how the compiler should parse calls to this function. This means prototypes have no effect if the function call is compiled before the function declaration has been seen by the compiler or if the function to call is only determined at runtime (e.g. because it's called as a method or through a reference).
With sub
, a prototype comes directly after the function name (if any). Function::Parameters
reserves this spot for the parameter list. To specify a prototype, put it as the first attribute (e.g. fun foo :(&$$)
). This is syntactically unambiguous because normal attributes need a name after the colon.
You can also use an attribute named prototype
(e.g. fun foo :prototype(&$$)
). In that case it does not have to be the first attribute. This syntax is also compatible with sub
in perl 5.20 and newer.
Parameter list
The parameter list is a list of variables enclosed in parentheses, except it's actually a bit more complicated than that.
Instead of a full variable name (such as $foo
or @bar
) you can write just the sigil ($
, @
, or %
). This has the effect of creating an unnamed parameter, which is useful in functions that are called with a certain number of arguments but want to ignore one or more of them. This trick works for invocants, slurpies, and positional parameters (see below). You can't have unnamed named parameters for what I hope are obvious reasons.
A parameter list can include the following 6 parts, all of which are optional:
- 1. Invocant
-
This is a scalar variable followed by a colon (
:
) and no comma. If an invocant is present in the parameter list, the first element of@_
is automaticallyshift
ed off and placed in this variable. This is intended for methods:method new($class: %init) { return bless { %init }, $class; } method throw($self:) { die $self; }
- 2. Required positional parameters
-
The most common kind of parameter. This is simply a comma-separated list of scalars, which are filled from left to right with the arguments that the caller passed in:
fun add($x, $y) { return $x + $y; } say add(2, 3); # "5"
- 3. Optional positional parameters
-
Parameters can be marked as optional by putting an equals sign (
=
) and an (optional) expression (the "default argument") after them. If no corresponding argument is passed in by the caller, the default argument will be used to initialize the parameter:fun scale($base, $factor = 2) { return $base * $factor; } say scale(3, 5); # "15" say scale(3); # "6"
Using just a
=
with no expression after is equivalent to specifying= undef
, i.e. the corresponding parameter is optional and has a default value ofundef
.The default argument is not cached. Every time a function is called with some optional arguments missing, the corresponding default arguments are evaluated from left to right. This makes no difference for a value like
2
but it is important for expressions with side effects, such as reference constructors ([]
,{}
) or function calls.Default arguments see not only the surrounding lexical scope of their function but also any preceding parameters. This allows the creation of dynamic defaults based on previous arguments:
method set_name($self: $nick = $self->default_nick, $real_name = $nick) { $self->{nick} = $nick; $self->{real_name} = $real_name; } $obj->set_name("simplicio"); # same as: $obj->set_name("simplicio", "simplicio");
Because default arguments are actually evaluated as part of the function body, you can also do silly things like this:
fun foo($n = return "nope") { "you gave me $n" } say foo(2 + 2); # "you gave me 4" say foo(); # "nope"
- 4. Required named parameters
-
By putting a colon (
:
) in front of a parameter you can make it named instead of positional:fun rectangle(:$width, :$height) { ... } rectangle(width => 2, height => 5); rectangle(height => 5, width => 2); # same thing!
That is, the caller must specify a key name in addition to the value, but in exchange the order of the arguments doesn't matter anymore. As with hash initialization, you can specify the same key multiple times and the last occurrence wins:
rectangle(height => 1, width => 2, height => 2, height => 5); # same as: rectangle(width => 2, height => 5);
You can combine positional and named parameters as long as the positional parameters come first:
fun named_rectangle($name, :$width, :$height) { ... } named_rectangle("Avocado", width => 0.5, height => 1.2);
- 5. Optional named parameters
-
As with positional parameters, you can make named parameters optional by specifying a default argument (or nothing, which is equivalent to
undef
) after an equals sign (=
):fun rectangle(:$width, :$height, :$color = "chartreuse") { ... } rectangle(height => 10, width => 5); # same as: rectangle(height => 10, width => 5, color => "chartreuse");
fun get($url, :$cookie_jar = HTTP::Cookies->new(), :$referrer = $url) { ... } my $data = get "http://www.example.com/", referrer => undef; # overrides $referrer = $url
The above example shows that passing any value (even
undef
) will override the default argument. - 6. Slurpy parameter
-
Finally you can put an array or hash in the parameter list, which will gobble up the remaining arguments (if any):
fun foo($x, $y, @rest) { ... } foo "a", "b"; # $x = "a", $y = "b", @rest = () foo "a", "b", "c"; # $x = "a", $y = "b", @rest = ("c") foo "a", "b", "c", "d"; # $x = "a", $y = "b", @rest = ("c", "d")
If you combine this with named parameters, the slurpy parameter will end up containing all unrecognized keys:
fun bar(:$size, @whatev) { ... } bar weight => 20, size => 2, location => [0, -3]; # $size = 2, @whatev = ('weight', 20, 'location', [0, -3])
Apart from the shift
performed by the invocant, all of the above leave @_
unchanged; and if you don't specify a parameter list at all, @_
is all you get.
Keyword
The keywords provided by Function::Parameters
are customizable. Since Function::Parameters
is actually a pragma, the provided keywords have lexical scope. The following import variants can be used:
use Function::Parameters ':strict'
-
Provides the keywords
fun
andmethod
(described below) and enables argument checks so that calling a function and omitting a required argument (or passing too many arguments) will throw an error. use Function::Parameters
-
Provides the keywords
fun
andmethod
(described below) and enables "lax" mode: Omitting a required argument sets it toundef
while excess arguments are silently ignored. use Function::Parameters { KEYWORD1 => TYPE1, KEYWORD2 => TYPE2, ... }
-
Provides completely custom keywords as described by their types. A "type" is either a string (one of the predefined types
function
,method
,classmethod
,function_strict
,method_strict
,classmethod_strict
) or a reference to a hash with the following keys:defaults
-
Valid values: One of the predefined types
function
,method
,classmethod
,function_strict
,method_strict
,classmethod_strict
. This will set the defaults for all other keys from the specified type, which is useful if you only want to override some properties:use Function::Parameters { defmethod => { defaults => 'method', shift => '$this' } };
This example defines a keyword called
defmethod
that works like the standardmethod
keyword, but the implicit object variable is called$this
instead of$self
.Using the string types directly is equivalent to
defaults
with no further customization:use Function::Parameters { foo => 'function', # like: foo => { defaults => 'function' }, bar => 'function_strict', # like: bar => { defaults => 'function_strict' }, baz => 'method_strict', # like: baz => { defaults => 'method_strict' }, };
name
-
Valid values:
optional
(default),required
(all functions defined with this keyword must have a name), andprohibited
(functions defined with this keyword must be anonymous). runtime
-
Valid values: booleans. If enabled, this keyword takes effect at runtime, not compile time:
use Function::Parameters { fun => { defaults => 'function_strict', runtime => 1 } }; say defined &foo ? "defined" : "not defined"; # not defined fun foo() {} say defined &foo ? "defined" : "not defined"; # defined
&foo
is only defined afterfun foo() {}
has been reached at runtime.CAVEAT: A future version of this module may enable
runtime => 1
by default for methods. shift
-
Valid values: strings that look like scalar variables. This lets you specify a default invocant, i.e. a function defined with this keyword that doesn't have an explicit invocant in its parameter list will automatically
shift
its first argument into the variable specified here. invocant
-
Valid values: booleans. If you set this to a true value, the keyword will accept invocants in parameter lists; otherwise specifying an invocant in a function defined with this keyword is a syntax error.
attributes
-
Valid values: strings containing (source code for) attributes. This causes any function defined with this keyword to have the specified attributes (in addition to any attributes specified in the function definition itself).
default_arguments
-
Valid values: booleans. This property is on by default; use
default_arguments => 0
to turn it off. This controls whether optional parameters are allowed. If it is turned off, using=
in parameter lists is a syntax error. check_argument_count
-
Valid values: booleans. If turned on, functions defined with this keyword will automatically check that they have been passed all required arguments and no excess arguments. If this check fails, an exception will by thrown via
Carp::croak
. check_argument_types
-
Valid values: booleans. This property is on by default; use
check_argument_types => 0
to turn it off. This controls whether functions defined with this keyword automatically check that the arguments they are passed pass the declared type constraints (if any). See "Experimental feature: Types" below. strict
-
Valid values: booleans. This turns on both
check_argument_count
andcheck_argument_types
. reify_type
-
Valid values: code references. The function specified here will be called to turn type annotations into constraint objects (see "Experimental feature: Types" below). It will receive two arguments: a string containing the type description, and the name of the current package.
The default type reifier is equivalent to:
sub { require Moose::Util::TypeConstraints; Moose::Util::TypeConstraints::find_or_create_isa_type_constraint($_[0]) }
The predefined type
function
is equivalent to:{ name => 'optional', default_arguments => 1, strict => 0, invocant => 0, runtime => 0, }
These are all default values, so
function
is also equivalent to{}
.method
is equivalent to:{ defaults => 'function', attributes => ':method', shift => '$self', invocant => 1, # runtime => 1, ## possibly in a future version of this module }
classmethod
is equivalent to:{ defaults => 'method', shift => '$class', }
function_strict
,method_strict
, andclassmethod_strict
are likefunction
,method
, andclassmethod
, respectively, but withstrict => 1
.
Plain use Function::Parameters
is equivalent to use Function::Parameters { fun => 'function', method => 'method' }
.
use Function::Parameters qw(:strict)
is equivalent to use Function::Parameters { fun => 'function_strict', method => 'method_strict' }
.
Introspection
You can ask a function at runtime what parameters it has. This functionality is available through the function Function::Parameters::info
(which is not exported, so you have to call it by its full name). It takes a reference to a function, and returns either undef
(if it knows nothing about the function) or a Function::Parameters::Info object describing the parameter list.
Note: This feature is implemented using Moo, so you'll need to have Moo installed if you want to call Function::Parameters::info
(alternatively, if Moose is already loaded by the time Function::Parameters::info
is first called, it will use that instead).
See Function::Parameters::Info for examples.
Wrapping Function::Parameters
If you want to write a wrapper around Function::Parameters
, you only have to call its import
method. Due to its pragma nature it always affects the file that is currently being compiled.
package Some::Wrapper;
use Function::Parameters ();
sub import {
Function::Parameters->import;
# or Function::Parameters->import(@custom_import_args);
}
Experimental feature: Types
An experimental feature is now available: You can annotate parameters with types. That is, before each parameter you can put a type specification consisting of identifiers (Foo
), unions (... | ...
), and parametric types (...[...]
). Example:
fun foo(Int $n, ArrayRef[Str | CodeRef] $cb) { ... }
If you do this, the type reification function corresponding to the keyword will be called to turn the type (a string) into a constraint object. The default type reifier simply loads Moose and forwards to Moose::Util::TypeConstraints::find_or_parse_type_constraint
, which creates Moose types.
If you are in "lax" mode, nothing further happens and the types are ignored. If you are in "strict" mode, Function::Parameters
generates code to make sure any values passed in conform to the type (via $constraint->check($value)
).
In addition, these type constraints are inspectable through the Function::Parameters::Info object returned by Function::Parameters::info
.
Experimental experimental feature: Type expressions
An even more experimental feature is the ability to specify arbitrary expressions as types. The syntax for this is like the literal types described above, but with an expression wrapped in parentheses (( EXPR )
). Example:
fun foo(('Int') $n, ($othertype) $x) { ... }
Every type expression must return either a string (which is resolved as for literal types), or a type constraint object (providing check
and get_message
methods).
Note that these expressions are evaluated (once) at parse time (similar to BEGIN
blocks), so make sure that any variables you use are set and any functions you call are defined at parse time.
How it works
The module is actually written in C and uses PL_keyword_plugin
to generate opcodes directly. However, you can run perl -MO=Deparse ...
on your code to see what happens under the hood. In the simplest case (no argument checks, possibly an invocant, required positional/slurpy parameters only), the generated code corresponds to:
fun foo($x, $y, @z) { ... }
# ... turns into ...
sub foo { my ($x, $y, @z) = @_; sub foo; ... }
method bar($x, $y, @z) { ... }
# ... turns into ...
sub bar :method { my $self = shift; my ($x, $y, @z) = @_; sub bar; ... }
BUGS AND INCOMPATIBILITIES
A future version of this module may enable runtime => 1
by default for methods. If this would break your code, please send me a note or file a bug on RT.
SUPPORT AND DOCUMENTATION
After installing, you can find documentation for this module with the perldoc command.
perldoc Function::Parameters
You can also look for information at:
- MetaCPAN
- RT, CPAN's request tracker
-
http://rt.cpan.org/NoAuth/Bugs.html?Dist=Function-Parameters
- AnnoCPAN, Annotated CPAN documentation
- CPAN Ratings
- Search CPAN
SEE ALSO
AUTHOR
Lukas Mai, <l.mai at web.de>
COPYRIGHT & LICENSE
Copyright 2010-2014 Lukas Mai.
This program is free software; you can redistribute it and/or modify it under the terms of either: the GNU General Public License as published by the Free Software Foundation; or the Artistic License.
See http://dev.perl.org/licenses/ for more information.