Why T::fn2 has only one parameter when it was called with two arguments?

Viewed 60

I have next script:

package T;
use strict;
use warnings;

sub fn1 {
    my( $var1, $var2 ) =  @_;
    T::fn2 $var1, $var2;
}

sub fn2 {
    print ">>@_<<"; # >>x1<<
}

package main;
use strict;
use warnings;

T::fn1 'x1', 'x2'; # >>x1<<

Here T::fn2 is called with two arguments but it get only one parameter.

I understand that I call forward subroutine which is not visible at time of parsing and is counted as bareword.

But I have use strict, use warnings so I expect warning is issued or program should not work at all instead it works incorrectly.

So Why it is still working and T::fn2 is called actually with one argument?

perl version is 5.30.3

1 Answers

Run

perl -MO=Deparse,-p

to see how the compiler understands the code:

sub fn1 {
    (my($var1, $var2) = @_);
    ($var1->T::fn2, $var2);
}

So, the call is interpreted as the indirect object notation of a method call, and the subroutine returns two values: the result of the method call and $var2.


To make it work correctly you have two choices:

  1. Use parentheses around subroutine arguments

    T::fn2($var1, $var2);

  2. Make sure the function is declared before it's called

sub fn2 {
    print ">>@_<<";
}

sub fn1 {
    my ($var1, $var2) =  @_;
    T::fn2 $var1, $var2;
}
  1. Make sure the function is declared before it's called (forward declaration)
sub fn2;

sub fn1 {
    my ($var1, $var2) =  @_;
    T::fn2 $var1, $var2;
}

sub fn2 {
    print ">>@_<<";
}
Related