Lukas Mai > Function-Parameters-1.00_01 > Function::Parameters

Download:
Function-Parameters-1.00_01.tar.gz

Dependencies

Annotate this POD

CPAN RT

New  3
Open  0
View/Report Bugs
Module Version: 1.00_01   Source   Latest Release: Function-Parameters-1.0402

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):

  1. The keyword introducing the function.
  2. The function name (optional).
  3. The parameter list (optional).
  4. The prototype (optional).
  5. The attribute list (optional).
  6. 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.

Name

If present, it specifies the name of the function being defined. As with sub, if a name is present, 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). If no name is present, the declaration is an expression that evaluates to a reference to the function in question. No surprises here either.

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.

Parameter list

The parameter list is a list of variables enclosed in parentheses, except it's actually a bit more complicated than that. 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 automatically shifted 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 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"

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 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 and method (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 and method (described below) and enables "lax" mode: Omitting a required argument sets it to undef 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:

name

Valid values: optional (default), required (all functions defined with this keyword must have a name), and prohibited (functions defined with this keyword must be anonymous).

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.

The predefined type function is equivalent to:

 {
   name => 'optional',
   invocant => 0,
   default_arguments => 1,
   check_argument_count => 0,
 }

These are all default values, so function is also equivalent to {}.

method is equivalent to:

 {
   name => 'optional',
   shift => '$self',
   invocant => 1,
   attributes => ':method',
   default_arguments => 1,
   check_argument_count => 0,
 }

classmethod is equivalent to:

 {
   name => 'optional',
   shift => '$class',
   invocant => 1,
   attributes => ':method',
   default_arguments => 1,
   check_argument_count => 0,
 }

function_strict, method_strict, and classmethod_strict are like function, method, and classmethod, respectively, but with check_argument_count => 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' }.

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);
 }

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; ... }

AUTHOR ^

Lukas Mai, <l.mai at web.de>

COPYRIGHT & LICENSE ^

Copyright 2010, 2011, 2012 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.

syntax highlighting: