Wednesday, January 5, 2011

perl: subroutines with prototypes(parameter)

sub ok ($;$) {  } and sub is ($$;$) { }

Those are subroutines with prototypes. `sub NAME(PROTO)`

`sub ok ($;$)`
Requires one mandatory argument and an optional one. They are
separated by a semi-colon in the prototype definition. The arguments
will be considered in scalar context (due to the `$`).

`sub is ($$;$)`
Requires two mandatory arguments and an optional one. All of them will
be considered in scalar context.



Perl's prototypes are not the prototypes in other languages. Other languages use prototypes to define, name and type the arguments to a subroutine. Perl prototypes are about altering the context in which the subroutine's arguments are evaluated, instead of the normal list context. They are fraught with peril, full of traps and should not be used without considerable thought. Perl prototypes should not be used merely as a check that the right arguments have been passed in. For that use a module such as Params::Validate.

The prototype of a function can be queried by calling prototype(). Prefix built-in functions with "CORE::". prototype("CORE::abs").

A subroutine's prototype is defined in its declaration, and enforces constraints on the interpretation of arguments passed to it. For example:

sub twice($) {
  return 2 * $_[0];
}


The subroutine above will accept only one argument, and will try to use non-scalar arguments given to it in a scalar context. For example, if you pass it in an array it will evaluate it in scalar context getting its length.

my @foo = (1, 2, 3);
print twice(@foo); # 2 * scalar @foo which is 6


Uses of prototypes in the wild include Test::More.

sub ok ($;$);


This allows one to test the length of a list.

ok( @foo, '@foo is not empty' );


Or compare the length of two lists.

sub is ($$;$);
is( @foo, @bar, '@foo and @bar have the same length' );


List::Util uses prototypes to simulate the behaviors of list processing functions like map and grep.

sub first (&@);
print first { $_ eq 'foo' } @bar;

Traps

  • Prototypes do not work on methods.
  • Prototypes do not work on function references.
  • Calling a function with a leading & (&foo) disables prototypes. But you shouldn't be calling functions like that.

No comments: