Prototypes and anonymous subroutines

B

Brad Baxter

In the synopsis of perlsub, it says the following:

To define an anonymous subroutine at runtime:

$subref = sub BLOCK; # no proto
$subref = sub (PROTO) BLOCK; # with proto
$subref = sub : ATTRS BLOCK; # with attributes
$subref = sub (PROTO) : ATTRS BLOCK; # with proto and
attributes

Then later is this:

Prototypes

Perl supports a very limited kind of compile-time argument
checking using function prototyping. If you declare

sub mypush (\@@)

then "mypush()" takes arguments exactly like "push()"
does. The function declaration must be visible at compile
time. The prototype affects only interpretation of new-
style calls to the function, where new-style is defined as
not using the "&" character. In other words, if you call
it like a built-in function, then it behaves like a built-
in function. If you call it like an old-fashioned subrou-
tine, then it behaves like an old-fashioned subroutine.
It naturally falls out from this rule that prototypes have
no influence on subroutine references like "\&foo" or on
indirect subroutine calls like "&{$subref}" or "$sub-
ref->()".

That last sentence seems somewhat contradictory to the
synopsis, because if prototypes have no influence on indirect
subroutine calls, then why be able to define them for anonymous
subroutines? For example:
perl -le'sub n($$){print@_};n(1,2)'
12
.... as expected
perl -le'sub n($){print@_};n(1,2)'
Too many arguments for main::n at -e line 1, at end of line
.... as expected
perl -le'$an=sub ($$){print@_};$an->(1,2)'
12
.... as expected
perl -le'$an=sub ($){print@_};$an->(1,2)'
12
.... expected an error, but prototype ignored?
perl -le'sub n(\@){print$_[0][0]};n([1,2])'
Type of arg 1 to main::n must be array (not single ref constructor) at
-e line 1, at end of line
.... as expected
perl -le'$an=sub (\@){print$_[0][0]};$an->([1,2])'
1
.... prototype ignored


So a couple of questions:

1. If prototypes are ignored for anonymous subroutines,
why be able to define them?

2. Am I missing a calling convention that does not ignore
them?
 
G

Greg Bacon

: So a couple of questions:
:
: 1. If prototypes are ignored for anonymous subroutines,
: why be able to define them?

You can make them work (see below), but maybe it was a speculative
development path that deadended.

: 2. Am I missing a calling convention that does not ignore
: them?

It's ugly, but consider

$ perl -le 'BEGIN { *n = sub ($) { print @_ } } n(1,2)'
Too many arguments for main::n at -e line 1, at end of line
Execution of -e aborted due to compilation errors.

Greg
 
S

Skye Shaw!@#$

: So a couple of questions:
:
: 1. If prototypes are ignored for anonymous subroutines,
: why be able to define them?

Why bother defining them?
: 2. Am I missing a calling convention that does not ignore
: them?

I believe it it because prototyping is a compile time feature. The
anonymous subroutines examples you provided are assignment statements,
and therefore get evaluated at runtime.
 
S

Skye Shaw!@#$

: So a couple of questions:
:
: 1. If prototypes are ignored for anonymous subroutines,
: why be able to define them?

You can make them work (see below), but maybe it was a speculative
development path that deadended.

: 2. Am I missing a calling convention that does not ignore
: them?

It's ugly, but consider

$ perl -le 'BEGIN { *n = sub ($) { print @_ } } n(1,2)'
Too many arguments for main::n at -e line 1, at end of line
Execution of -e aborted due to compilation errors.

Hummm... BEGIN{} forces compile time evaluation, so the prototype is
evaluated in this case.
 
B

Brad Baxter

: So a couple of questions:
:
: 1. If prototypes are ignored for anonymous subroutines,
: why be able to define them?

You can make them work (see below), but maybe it was a speculative
development path that deadended.

: 2. Am I missing a calling convention that does not ignore
: them?

It's ugly, but consider

$ perl -le 'BEGIN { *n = sub ($) { print @_ } } n(1,2)'
Too many arguments for main::n at -e line 1, at end of line
Execution of -e aborted due to compilation errors.

Ah, very interesting. Carried further (for no reason other than
curiosity), I see
perl -le 'BEGIN { $an = sub ($) { print @_ }; *n=\&$an } n(1,2)'
Too many arguments for main::n at -e line 1, at end of line
Execution of -e aborted due to compilation errors.
perl -le 'BEGIN { $an = sub ($) { print @_ } } *n=\&$an; n(1,2)'
12
 
B

Brad Baxter

Why bother defining them?

Why bother documenting them? :)

Which was the point I was working around to: if it's not
a feature that can be reasonably used, perhaps it shouldn't
be quite so prominently featured in the docs. As Greg
mentioned, it may have been intended to work more simply
for anonymous subs, but then dropped.

Cheers,
 
B

Brad Baxter

Too many arguments for main::n at -e line 1, at end of line
Execution of -e aborted due to compilation errors.


12

Of course, I meant:
perl -le 'my $an; BEGIN { $an = sub ($) { print @_ }; *n=$an } n(1,2)'
Too many arguments for main::n at -e line 1, at end of line
perl -le 'my $an;BEGIN { $an = sub ($) { print @_ } } *n=$an; n(1,2)'
12
 
B

Brian McCauley

: So a couple of questions:
:
: 1. If prototypes are ignored for anonymous subroutines,
: why be able to define them?

You can make them work (see below), but maybe it was a speculative
development path that deadended.

: 2. Am I missing a calling convention that does not ignore
: them?

It's ugly, but consider

$ perl -le 'BEGIN { *n = sub ($) { print @_ } } n(1,2)'
Too many arguments for main::n at -e line 1, at end of line
Execution of -e aborted due to compilation errors.

Have encountered obscure edge cases where I've used this sort of
thing. But they are rare.

I've also abused prototypes (in a similar way to the way sort() does)
as a poor-man's metadata by using the explicit prototype() function.
For an example see String::Interpolate.
 
B

Brad Baxter

Have encountered obscure edge cases where I've used this sort of
thing. But they are rare.

I've also abused prototypes (in a similar way to the way sort() does)
as a poor-man's metadata by using the explicit prototype() function.
For an example see String::Interpolate.

Fair enough. Thanks.
 
U

Uri Guttman

GB> In article <[email protected]>,

GB> : So a couple of questions:
GB> :
GB> : 1. If prototypes are ignored for anonymous subroutines,
GB> : why be able to define them?

GB> You can make them work (see below), but maybe it was a speculative
GB> development path that deadended.

GB> : 2. Am I missing a calling convention that does not ignore
GB> : them?

GB> It's ugly, but consider

GB> $ perl -le 'BEGIN { *n = sub ($) { print @_ } } n(1,2)'
GB> Too many arguments for main::n at -e line 1, at end of line
GB> Execution of -e aborted due to compilation errors.

that can be done with a module and use as well. asssigning a code ref to
a type glob is how exporting is done in general. and the prototype is
available to the compiler from the use point onward to end of file. this
is how exported subs with code blocks for an arg work as do others that
take only 1 arg as you showed above. it is one of the few cases where
prototypes are useful.

uri
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,819
Latest member
masterdaster

Latest Threads

Top