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>