views:

2393

answers:

3

In another question a member asserted "I would advice you not to use prototypes. They have their uses, but not for most cases and definitely not in this one."

Can anyone elaborate on why this might be true (or otherwise)? I almost always supply prototypes for my Perl functions, and I've never before seen anyone else say anything bad about using them.

+26  A: 

The problem is that Perl's function prototypes don't do what people think they do. Their purpose is to allow you to write functions that will be parsed like Perl's built-in functions.

First of all, method calls completely ignore prototypes. If you're doing OO programming, it doesn't matter what prototype your methods have. (So they shouldn't have any prototype.)

Second, prototypes aren't strictly enforced. If you call a subroutine with &function(...), the prototype is ignored. So they don't really provide any type safety.

Third, they're spooky action-at-a-distance. (Especially the $ prototype, which causes the corresponding parameter to be evaluated in scalar context, instead of the default list context.)

In particular, they make it hard to pass parameters from arrays. For example:

my @array = (1,2,3);

foo(@array);
foo(@array[0..1]);
foo($array[0], $array[1], $array[2]);

sub foo ($;$$) { print "@_\n" }

foo(@array);
foo(@array[0..1]);
foo($array[0], $array[1], $array[2]);

prints:

1 2 3
1 2
1 2 3
3
2
1 2 3

along with 3 warnings about main::foo() called too early to check prototype. The problem is that an array (or array slice) evaluated in scalar context returns the length of the array.

If you need to write a function that acts like a built-in, use a prototype. Otherwise, don't use prototypes.

Note: Perl 6 will have completely revamped and very useful prototypes. This answer applies only to Perl 5.

cjm
But they still provide a useful check that your caller and the sub are using the same number of arguments, so what's wrong with that?
Paul Tomblin
Alnitak
No; the general consensus is that Perl function prototypes provide essentially no benefit. You may as well not bother with them, at least in Perl 5. Perl 6 might be a different (better) story.
Jonathan Leffler
There are better ways to validate arguments, such as the Params::Validate module: http://search.cpan.org/~drolsky/Params-Validate-0.91/lib/Params/Validate.pm
friedo
+27  A: 

Prototypes aren't bad if used correctly. The difficulty is that Perl's prototypes don't work the way people often expect them to. People with a background in other programming languages tend to expect prototypes to provide a mechanism for checking that function calls are correct: that is, that they have the right number and type of arguments. Perl's prototypes are not well-suited for this task. It's the misuse that's bad. Perl's prototypes have a singular and very different purpose:

Prototypes allow you to define functions that behave like built-in functions.

  • Parentheses are optional.
  • Context is imposed on the arguments.

For example, you could define a function like this:

sub mypush(\@@) { ... }

and call it as

mypush @array, 1, 2, 3;

without needing to parenthesize the argument list or write the \ to take a reference to the array.

In a nutshell, prototypes let you create your own syntactic sugar. For example the Moose framework uses them to emulate a more typical OO syntax.

This is very useful but prototypes are very limited:

  • They have to be visible at compile-time.
  • They can be bypassed.
  • Propagating context to arguments can cause unexpected behavior.
  • They can make it difficult to call functions using anything other than the strictly prescribed form.

See Protoypes in perlsub for all the gory details.

Michael Carman
I've accepted this answer because I feel it best answers the question - prototypes aren't intrinsically bad, it's just how you use them.
Alnitak
Moose prototypes on the otherhand, are /awesome/ http://p3rl.org/MooseX::Declare http://p3rl.org/MooseX::Method::Signatures
Kent Fredric
+8  A: 

I agree with the above two posters. In general, using $ should be avoided. Prototypes are only useful when using block arguments (&), globs (*), or reference prototypes (\@, \$, \%, \*)

Leon Timmermans
Aren't you afraid people feel compelled to downvote your answer to ensure that the word "above" in your answer will always apply?
bzlm
You're very childish to downvote me because of that. You known just as well as I do that there's no way for me to catch up when I'm ten votes behind.
Leon Timmermans