Search code examples
perlargumentssubroutine

Not enough arguments when redefining a subroutine


When I redefine my own subroutine (and not a Perl built-in function), as below :

perl -ce 'sub a($$$){} sub b {a(@_)}'

I get this error :

Not enough arguments for main::a at -e line 1, near "@_)"

I'm wondering why.

Edit :

The word "redefine" is maybe not well chosen. But in my case (and I probably should have explained what I was trying to do originally), I want to redefine (and here "redefine" makes sense) the Test::More::is function by printing first Date and Time before the test result.

Here's what I've done :

Test::More.pm :

sub is ($$;$) {
    my $tb = Test::More->builder;

    return $tb->is_eq(@_);
}


MyModule.pm :

sub is ($$;$) {
   my $t    = gmtime(time);
   my $date = $t->ymd('/').' '.$t->hms.' ';

   print($date);
   Test::More::is(@_);
}

Solution

  • In Perl, prototypes don't validate arguments so much as alter parsing rules. $$;$ means the sub expects the caller to match is(EXPR, EXPR) or is(EXPR, EXPR, EXPR).

    In this case, bypassing the prototype is ideal.

    sub is($$;$) {
       print gmtime->strftime("%Y/%m/%d %H:%M:%S ");
       return &Test::More::is(@_);
    }
    

    Since you don't care if Test::More::is modifies yours @_, the following is a simple optimization:

    sub is($$;$) {
       print gmtime->strftime("%Y/%m/%d %H:%M:%S ");
       return &Test::More::is;
    }
    

    If Test::More::is uses caller, you'll find the following useful:

    sub is($$;$) {
       print gmtime->strftime("%Y/%m/%d %H:%M:%S ");
       goto &Test::More::is;
    }