I think subroutine signatures don't need arguments count checking

I think subroutine signatures don't need arguments count checking,
because performance is more important than utility.

Subroutine signature should be optimized from performance perspective, not utility.
Arguments count checking is one logic, so it damage run time performance.

And I like simple and compact syntax.

  sub foo($x, $y) {
    ...
  }
  
  # same as
  sub foo {
    my ($x, $y) = @_;
  }
  sub foo($x = 0, $y = 0) {
    ...
  }

  # same as
  sub foo {
    my ($x, $y) = @_;
    $x //= 0;
    $y //= 0;
  }

At first, it is good that only small syntax is introduced, not complex one.

And getting arguments count is optimized.

  # Should be fast
  my $count = @_;

  # Slow is ok in subroutine signature
  my $first = $_[0]
  my $second = $_[1]

Arguments count checking should be user responsibility, not default feature.

In static type language can do arguments count checking in compile time.
But in dynamic type language arguments count checking is run time cost.


9 Comments

In relative terms, the time required to check that the number of arguments given matches the signature is probably insignificant.

Have you run any benchmark?

If you don't want the runtime to check for argument count, you can say:

sub foo($x,$y,@) { ... }

and the "too many arguments" check won't be compiled (I just checked with B::Concise).

I think argument checks are a good thing because correctness is more important than speed (who cares how fast you are at getting the wrong result?).

Checking the arguments manually is annoying boilerplate code that no user wants to bother with. It's much better to be able to abstract it away and have the language do it for you automatically.

That said, Function::Parameters supports both: use Function::Parameters qw(:strict); enables checks, but use Function::Parameters qw(:lax) doesn't, just like my ($x, $y, $z) = @_;.

Hmmm.

Yuki, you seem to have a strong opinion here.
Not that there is anything wrong with having strong opinions --- but it would be much better if you could at least point to some facts that support your opinion.
Like, say, benchmarks. Like, say, code (show the source code!) that does run appreciably faster without argument checking.

Performance at all costs of programmer usability, maintenance and bug finding ease would mean that you write highly optimized, hand-polished assembler running on the bare metal of the machine, with no OS to slow things down, no running on virtual machines as they have overhead, no compiling every time a script starts and no dynamic language, which cannot be as optimized as one where the compiler knows the exact types to expect.

And not using subroutines in Perl:
#! /usr/bin/perl   # perl 5.22.1 on Linux
use strict;
use warnings;
use Benchmark 'cmpthese';
my $count = -5;
sub testsub { return 1 + 1 }
cmpthese(
    $count,
    {   'without subroutine' => 'my $a = 1 + 1;',
        'with subroutine'    => 'my $a = testsub()',
    }
);
                         Rate    with subroutine without subroutine
with subroutine     7208764/s                 --               -80%
without subroutine 36384252/s               405%                 --
Just so you know.


If argument checking is optional, it should default to "on", because for almost all use cases that tiny bit of performance is not important at all; but less chances of bugs is important or very important to most use cases, and writing "no argumentchecking;" at the begin of your file is certainly not more onerous than "use strict; use warnings;".

Leave a comment

About Yuki Kimoto

user-pic I'm Yuki Kimoto, Japanese Perl programmer.I create Perl modules and applications. GitPrep, SPVM, DBIx::Custom, Validator::Custom, Test::Mojo, Mojolicious::Plugin::AutoRoute, etc.