dave_the_m has posted a long and very comprehensive thread to perl5-porters in which he outlines his plans for subroutine signatures. The plan is to get a consensus on the syntax of the various features and then to implement them over the next year. The goal is to have subroutine signatures out of experimental status by Perl 5.36. Whatever breaking of backwards compatibility with the existing (experimental) subroutines is necessary should go into 5.32.
I have mostly copied the Synopsis section of each mail here, and I really encourage you to look at the mails themselves which contain far more discussion of the proposed behaviours.
The separate threads are:
Here is a contrived example of a signature which demonstrates many of the proposals. Some of it will make more sense after each proposal has been read.
sub foo ( $self, # parameter declarations starting with '?' examine, # but don't consume any further arguments: ?*@args, # @args is set to the equivalent of @_ with one # arg shifted; i.e. like a slurpy but peeking ahead # and not actually consuming any args; the '*' means # that each @args element is aliased to a passed arg ?$peek_a, # $peek_a is bound to next arg but without consuming + it ??$has_a, # $has_a is set to true if there's an argument for $ +a $a, # normal scalar parameter ?{ print $a },# embedded code block - runs code; doesn't shift arg +s Dog $spot, # works the same as 'my Dog $spot' $b :shared, # you can use normal variable attributes $c :ro, # at compile time, $c in lvalue context croaks \@ary, # aliases @ary to a passed array reference \%hash, # aliases %hash to a passed hash reference *$scalar, # aliases $scalar to the next argument # Constraints and coercions: $d!, # croak if $d not defined $e isa Foo::Bar, # croak if $e isn't of that class $f is Int where $_ > 0, # croak if $f not a positive integer $x = 0, # a default value $y?, # short for $y = undef \@array?, # short for \@array = [] :$name1 = 0, :$name2 = 0, # consume name-value pairs (name1 => ..., name2 => . +...) @rest # slurp up any remaining arguments ) { .... }
sub f ($x :foo, $y :bar(baz) bar2(baz2), ...) { ... }
analogous to:
my $x :foo; my $y :bar(baz) bar2(baz2);
Perl should support parameter attributes.
What exactly should the semantics be? Lets first review the current syntax as applied to 'my' declarations:
my ($x, $y) :foo(foo_arg) :bar(bar_arg);
is roughly equivalent to
use attributes (); my ($x,$y); attributes->import(, __PACKAGE__, \$x, "foo(foo_arg)", "bar(bar_ar +g)"); attributes->import(, __PACKAGE__, \$y, "foo(foo_arg)", "bar(bar_ar +g)");
sub foo ( $pos1, # positional parameter; consumes 1 arg $pos2, # positional parameter; consumes 1 arg :$name1, # named parameter, consumes ("name1", value) arg +pair :$name2, # named parameter, consumes ("name2", value) arg +pair @rest, # consumes all unrecognised name/value pairs ) { ... }
This seems a popular feature request: give Perl 5 something similar to Perl 6's named parameters.
?$x peek ahead to the next arg ??$x peek ahead and see if there is a next arg ?@a peek ahead and copy all remaining args ?%h peek ahead and copy all remaining key/val arg pairs ?{ code } execute some code without consuming any args
Sometimes you want to find out some extra information about the arguments and the state of argument processing. With @_ available, this can be done, if messily; if @_ isn't populated (see the "@_ Suppression" thread), then it becomes harder/impossible, unless some other mechanisms are added.
@_ will not be set, unset or localised on entry to or exit from a signatured sub; it will still be the @_ of the caller. But any use of @_ within the lexical scope of sub a sub will warn.
sub foo { # the lexical vars $a, @b and %c are aliased to the things poi +nted # to by the reference values passed as the first three argumen +ts: \$a \@b, \%c, # $d is aliased to the fourth arg: *$d, # $e is aliased to the fifth arg, but at compile time, any us +e # of $e in lvalue context within this lexical scope is a compi +le # time error: *$e :ro, # the elements of @f are aliased to any remaining args, # i.e. a slurpy with aliasing ...: *@f # .. or a slurpy hash; every second remaining arg is aliased t +o # the hash's values: *%g ) { ... }
sub f( $self isa Foo::Bar, # croak unless $self->isa('Foo +::Bar'); $foo isa Foo::Bar?, # croak unless undef or of tha +t class $a!, # croak unless $a is defined $b is Int, # croak if $b not int-like $c is Int?, # croak unless undefined or in +t-like $d is PositiveInt, # user-defined type $e is Int where $_ >= 1, # multiple constraints $f is \@, # croak unless array ref $aref as ref ? $_ : [ $_ ] # coercions: maybe modify the +param ) { ...};
It seems that people express a desire to be able to write something like:
sub f (Int $x) { ... }
as a shorthand for for something like:
sub f ($x) { croak unless defined $x && !ref($x) && $x =~ /\A-?[0-9]+\Z/; ....; }
Similarly people want
sub f (Some::Arbitrary::Class $x) { ... }
as a shorthand for
sub f ($x) { croak unless defined $x && ref($x) && $x->isa(Some::Arbitrary::Class); ...; }
Furthermore, there are also Perl 6 generic constraints:
sub f ($x where * < 10*$y) { ... }
We need to determine and document how the various parts of a signature behave as regards to lexical scope, visibility, tainting and ordering of things like default expressions and constraints.
dave_the_m proposes for lexical scoping that:
sub f($a, $b, $c, ... ) { BODY; }
Is logically equivalent to:
sub f { my $a = ....; my $b = ....; my $c = ....; ....; BODY; }
In particular, each parameter element is independent taint-wise, and each parameter variable has been fully introduced and is visible to default expressions and the like in further parameters to the right of it.
This last post contains are a few random suggestions that people have made at various times.
In reply to Jumbo Signatures extensions discussion by Corion
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |