Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Given the warnings & strict modules, is it still considered poor form to declare subroutine prototypes? Thanks.

Replies are listed 'Best First'.
Re: subroutine prototypes still bad?
by Zaxo (Archbishop) on Jun 13, 2007 at 00:18 UTC

    The problem with prototypes is not that they are poor form, it's that they don't do what most people expect from their experience with Java or C. They are usually unnecessary in Perl, and if misused are the source of confusing bugs. Bugs particularly confusing to the person who wrote them.

    Perl prototypes override normal parsing of a sub's arguments. They can be used to prevent the flattening of arrays, for instance. Normally, in foo(@bar,@baz), the two arrays will be merged into a list of both their contents in order. If foo were given the prototype '\@@', however, @bar is treated as a unit, joining the argument list as a reference to itself. The foo() function will treat its arguments the way that push does.

    The empty prototype is a particularly interesting one. It causes Perl to try to unfold sub parsing and produce a constant at compile time. It can have profound effects on how a statement is parsed.

    I'm not clear on what you mean by your reference to strict and warnings. As far as I know, those are unrelated to prototypes, other than a few warnings which indicate that a prototype will not be honored or a sub call has ambiguous syntax.

    After Compline,
    Zaxo

      The way I put it is that prototypes let you write routines that act more like some of perl's built-ins. For example, you might want to write something that acts like this:
      # deal from the middle of the deck my $card = pop_random( @deck );

      And the real trouble with writing code like this is simply that it doesn't behave like regular perl code. A non-perl expert reading that line of code is likely to feel a vague sense of disquiet, a sense that they don't quite know what's going on. A perl expert reading it is going to immediately want to see the definition of pop_random, to make sure the prototype was used right.

      On the other hand, the slightly uglier semantics of pop_random( \@deck ); is much less likely to throw anyone off.

      (And yes, it's unfortunate that these were called "prototypes": I didn't understand what they were for a long time, because I expected them to be hints to the compiler to help catch errors if the wrong kind or arguments were passed.)

      So this means that the interpreter prefers to see all subroutines to be defined prior to being called?

        Yes, if they are prototyped. Otherwise, no.

        After Compline,
        Zaxo

Re: subroutine prototypes still bad?
by dmitri (Priest) on Jun 13, 2007 at 01:37 UTC
    It really depends on what you are doing. Some of the most useful things cannot be done without prototypes -- such as the wonderful Error.pm module that provides this syntactic sugar:
    try { try($something); } catch Exception with { };
    There are probably other examples. Of course, you should not use prototypes unless you know exactly why you are using them.

      It's gotten slightly better due to dave_m's work but what you wrote is usually a memory-leak magnet. Error.pm is a horrible module just because of the closure related leaks.

      ⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊

        Are you referring to the try inside a try? That inside "try" is meant to be some other function call. :)

        I have used Error.pm in long-running network daemons without many problems. I am aware that closures may cause memory leaks, but haven't run into one related to Error.pm

      That's actually a good example of why prototypes are *bad*. It looks so much like normal Perl code, one might be tempted to return from the catch block.

      sub { try { ... } catch Exception with { return 0; }; return 1; }

      However, a return in catch block only exits the catch block! The above function would always return 1.

        I think it depends on what you are used to. I recently had to write some Java code, and I found myself putting 'return' statements outside of try/catch, even though it's fine in Java.

        Since I use mostly Perl, this behavior does not confuse me at all.

      Hear hear. I've needed them exactly once (in NestedMap) and a good rule of thumb is to not write any code that you don't need.

      And before anyone says "why do you use strict and warnings then" - I need them to save me from my own stupid errors. I suppose that in theory I could remove them from my modules once they pass all their tests, but that means I have to put them back in when I change stuff later, and it also supposes that my tests are perfect.