6

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

sub function1($$)
{
   //snip
}

What does this mean in Perl?

Ether
  • 53,118
  • 13
  • 86
  • 159
sud03r
  • 19,109
  • 16
  • 77
  • 96

2 Answers2

16

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.

Community
  • 1
  • 1
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • thanks!! i almost figured out that. BTW why is it required, some kind of type and number checking on the parameters, is it? – sud03r Mar 20 '10 at 22:53
  • 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 Mar 20 '10 at 23:03
  • 3
    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 Mar 20 '10 at 23:11
  • 2
    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 Mar 20 '10 at 23:15
  • @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 Mar 20 '10 at 23:16
  • @Jonathan: I see them used when you want to accept a coderef without the `sub` prefix, e.g. `(&@)`, but that's really about it. In most cases, they cause too many headaches to bother with. – rjh Mar 20 '10 at 23:22
  • 2
    Don't use prototypes in Perl. There are very few exceptions to this rule. – Sinan Ünür Mar 20 '10 at 23:33
  • @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 Mar 20 '10 at 23:43
  • @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 Mar 21 '10 at 00:41
  • @rjh, @Jonathan: We discussed the pitfalls of prototypes here: http://stackoverflow.com/questions/297034/why-are-perl-function-prototypes-bad – Ether Mar 21 '10 at 02:54
  • 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 Mar 22 '10 at 15:19
11

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.

daotoad
  • 26,689
  • 7
  • 59
  • 100
jrockway
  • 42,082
  • 9
  • 61
  • 86