views:

206

answers:

2

I have been using Perl for some time, but today I came across this code:

sub function1($$)
{
   //snip
}

What does this mean in Perl?

+14  A: 

It is a function with a prototype that takes two scalar arguments.


There are strong arguments for not actually using Perl prototypes in general - as noted in the comments below. The strongest argument is probably:

There's a discussion on StackOverflow from 2008:

There's a possible replacement in the MooseX::Method::Signatures module.

Jonathan Leffler
thanks!! i almost figured out that. BTW why is it required, some kind of type and number checking on the parameters, is it?
Neeraj
Perl doesn't require prototypes; they are entirely optional. However, just as in C code, supplying prototypes can head off some errors which will otherwise remain undetected. On the whole, they are not used very often, in my experience - partly because they are a late addition to the language, and partly because Perl coders exploit (for good, on the whole) the flexibility of Perl subs without prototypes, and partly because people don't like to avoid errors automatically (they seem to prefer to find them the hard way).
Jonathan Leffler
Prototypes are not used in modern Perl because they are broken. How broken? Here's a recent question that illustrates just one of their numerous problems: http://stackoverflow.com/questions/2485106/why-do-printf-and-sprintf-behave-differently Prototypes are not used for type checking, they are hints to the compiler, and Perl will *coerce the caller's arguments to fit the prototype* even if they're wrong.
rjh
For a (much) more detailed warning about prototypes, read http://web.archive.org/web/20030704193247/http://perl.com/pub/a/language/misc/fmproto.html
rjh
@rjh: I hadn't seen that particular problem. Generally, if you're used to using functions with a prototype, then you don't run into issues. It is a bit of a surprise when something that looks like it should be 'normal' turns out not to be - sprintf() in the referenced question. That said, I have maybe one or two Perl files with prototypes in effect - I have several hundred with no prototypes.
Jonathan Leffler
rjh
Don't use prototypes in Perl. There are very few exceptions to this rule.
Sinan Ünür
@rjh: OK - I'm persuaded by your second URL (at web.archive.org). If I could double up-vote your comment, I would. I hadn't realized that I was accidentally erring on the side of sanity; I just assumed I was employing the other Perlish virtue of laziness.
Jonathan Leffler
@Jonathan: on the other hand, there's http://search.cpan.org/perldoc?MooseX::Method::Signatures and http://search.cpan.org/perldoc?signatures - both are fine to use (although somewhat new) and the former is a lot more powerful than prototypes.
rjh
@rjh, @Jonathan: We discussed the pitfalls of prototypes here: http://stackoverflow.com/questions/297034/why-are-perl-function-prototypes-bad
Ether
Prototypes are not in themselves evil. If people understood that they are compiler hints and nothing more, then there would be no problem with them. The problem lies in the name 'prototype' and the false expectations that it brings (type checking, primarily--note the suggestion that method signatures replace prototypes).
daotoad
+10  A: 

As the other answer mentions, the $$ declares a prototype. What the other answer doesn't say is what prototypes are for. They are not for input validation, they are hints for the parser.

Imagine you have two functions declared like:

sub foo($)  { ... }
sub bar($$) { ... }

Now when you write something ambiguous, like:

foo bar 1, 2

Perl knows where to put the parens; bar takes two args, so it consumes the two closest to it. foo takes one arg, so it takes the result of bar and the two args:

foo(bar(1,2))

Another example:

bar foo 2, 3

The same applies; foo takes one arg, so it gets the 2. bar takes two args, so it gets foo(2) and 3:

bar(foo(2),3)

This is a pretty important part of Perl, so dismissing it as "never use" is doing you a disservice. Nearly every internal function uses prototypes, so by understanding how they work in your own code, you can get a better understanding of how they're used by the builtins. Then you can avoid unnecessary parentheses, which makes for more pleasant-looking code.

Finally, one anti-pattern I will warn you against:

package Class;
sub new ($$) { bless $_[1] }
sub method ($) { $_[0]->{whatever} }

When you are calling code as methods (Class->method or $instance->method), the prototype check is completely meaningless. If your code can only be called as a method, adding a prototype is wrong. I have seen some popular modules that do this (hello, XML::Compile), but it's wrong, so don't do it. If you want to document how many args to pass, how about:

sub foo {
    my ($self, $a, $b) = @_; # $a and $b are the bars to fooify
    ....

or

use MooseX::Method::Signatures;

method foo(Bar $a, Bar $b) { # fooify the bars
    ....

Unlike foo($$), these are meaningful and readable.

jrockway