perl: perl subroutine prototypes are problematic, don't use them
authorStefano Lattarini <stefano.lattarini@gmail.com>
Tue, 5 Mar 2013 17:30:03 +0000 (18:30 +0100)
committerStefano Lattarini <stefano.lattarini@gmail.com>
Fri, 19 Apr 2013 09:08:18 +0000 (11:08 +0200)
commitc8a2bc7c7331bed33cc47187d04fbc144b860dff
treeb74fe15034e782f5254eb9b3aec868424db85a1e
parent9cbd5436781986a5a05c7bd214d68671b7cf5f31
perl: perl subroutine prototypes are problematic, don't use them

Basically, in perl, "subroutine prototypes" are not prototypes at all;
rather, they are a trick to allow user-defined subroutines that behave
like perl built-in functions.  For example, prototyped subroutines can
be called without parentheses, and can impose context on their arguments.

Such semantics can be useful in some selected situations, but might also
easily cause unexpected and harmful behaviours and side effects if we
try to use perl prototypes as we would use C prototypes.

See the excellent article "Far More than Everything You've Ever Wanted
to Know about Prototypes in Perl" by Tom Christiansen for more detailed
information:

    <http://www.perlmonks.org/?node_id=861966>
    <http://web.archive.org/web/20080421062920/\
     library.n0i.net/programming/perl/articles/fm_prototypes>

It is important to note that modern perl allows a non-predeclared
subroutine to be called without the '&' character, as long as its
call uses proper parentheses:

    foo 'str', 2;   # will trigger errors if foo is not predeclared
    foo('str', 2);  # ok even if foo is not predeclared
    &foo('str', 2); # ditto; but the '&' is old-style and redundant

Note also that the prototype indicating "no argument":

    sub func() { ... }

can actually be useful, and has no discernible downsides, so we'll
keep using it where it makes sense.

Also, in few, selected cases, we *want* to have subroutines behave like
perl builtins (e.g., we want the 'append_exeext' function to be able
to take a code block as first argument).  In such cases, we will of
course continue to make use of perl subroutine prototypes.

Let's finally see an example that might clarify the kind of problems the
use of subroutine prototypes in perl can cause.  This is just scratching
the surface; there are several other aspects, typically subtler and more
dangerous, that are not touched here.

If you have the prototyped subroutine definition:

    sub foo ($@)
    {
        my $s = shift;
        print "SCALAR: $s\n";
        print "ARRAY: @_\n";
    }

and call 'foo' in code like:

    @list = (-1, 0, 1);
    foo(@list);

you won't get a compile-time nor a runtime error (as a naive interpretation
of the "prototype" characterization would let you think).  Rather, the
prototype will cause the array '@list' will be coerced into scalar context
before being passed too 'foo', which means that its *length* (3) will be
passed to 'foo' as first argument; and since no further arguments are
present after '@list', that *void* will be coerced to an empty list before
being passed to 'foo'.

So code above will have the result of printing:

  SCALAR: 3
  ARRAY:

Quite tricky, and definitely a behaviour we don't want to rely on.

* automake.in: Delete most subroutine prototypes.  Fix few of the
remaining ones.  Related minor simplifications and adjustments.
* lib/gen-perl-protos: Adjust.

Signed-off-by: Stefano Lattarini <stefano.lattarini@gmail.com>
automake.in