@results = reverse myfunc 3, 5;
Without prototypes, this is the same as:
@results = reverse(myfunc(3, 5));
Without parentheses, Perl puts the righthand side of the subroutine
call into list context. You can use prototypes to change this
behavior. Here is a function that's prototyped to take just one
argument:
sub myfunc($);
@results = reverse myfunc 3, 5;
Now this is the same as:
@results = reverse(myfunc(3), 5);
Notice how the scalar prototype has altered the Perl parser! It grabs
only the next thing it sees, leaving what remains for whatever other
function is looking for arguments.
A void prototype like:
sub myfunc( );
will also alter the parser, causing no arguments to be passed to the
function. This works just like the time built-in.
That means that in the absence of parentheses, you cannot
know what is going on by casual inspection. Things that
look the same can quietly behave completely differently from one
another. Consider these declarations and assignments:
sub fn0( );
sub fn1($);
sub fnN(@);
$x = fn0 + 42;
$x = fn1 + 42;
$y = fnN fn1 + 42, fn0 + 42;
$y = fnN fn0 + 42, fn1 + 42;
$z = fn1 fn1 + 42, fn1 + 42;
$z = fnN fnN + 42, fnN + 42;
Astonishingly enough, those are parsed by the Perl compiler as though
they'd been written this way:
$x = fn0( ) + 42;
$x = fn1(42);
$y = fnN(fn1(42), fn0( ) + 42);
$y = fnN(fn0( ) + 42, fn1(42));
$z = fn1(fn1(42)), fn1(42);
$z = fnN(fnN(42, fnN(42)));
Without first looking closely at the prototypes and then thinking
really hard about how Perl's parser works, you'd never be able to
predict that. Maintainability would suffer horribly.
This is one strong argument for using more parentheses than might be
demanded by purely precedential concerns (or, alternatively, this is
an argument for avoiding prototypes).