Perlのエラーメッセージのコーナー。今回は
%s() called too early to check prototype
です。あるサブルーチンが、プロトタイプのチェックをするよりも早く呼びだされました、という警告です。

Toyota Prototype

 プロトタイプとは、サブルーチンで引数の型を宣言するものです。Perlでは引数が全部@_という特殊変数に入ってサブルーチンが呼ばれます。ですから、サブルーチンの引数が何個であるかを明示する必要はありません。また、Perlの変数は型がないので、型宣言も必要ありませんし、出来ません(Perl 6では事情が変わりました)。
 しかも、@_は呼び出し側と呼び出され側でメモリ空間を共有します。

 ここで、あえて人為的な制限を加えるのがプロトタイプ宣言です。以下のプログラムでは、サブルーチンmySubに、$$というプロトタイプを書くことで、スカラー2個を渡されることが明らかになっています。まずはうまくいくパターン。
#! /usr/local/bin/perl
# subroutineExample.pl -- サブルーチンの実験

use strict;
use warnings;
use 5.10.0;

sub mySub ($$) {
 my $n = shift;
 my $m = shift;
 say "引数 $n と $m を渡されました。二乗した和を返します。";
 return $n ** 2 + $m ** 2;
}

my $ret = mySub(2, 3);
say "戻り値は $ret でした。";

$ subroutineExample.pl
引数 2 と 3 を渡されました。二乗した和を返します。
戻り値は 13 でした。

 mySubは2と3を渡され、各々を2乗して4と9にし、それを足した13を返します。別に大丈夫ですね。ここでプロトタイプを無視し、引数を3個渡してみます。

#! /usr/local/bin/perl
# subroutineExample2.pl -- サブルーチンの実験2

use strict;
use warnings;
use 5.10.0;

sub mySub ($$) {
 my $n = shift;
 my $m = shift;
 say "引数 $n と $m を渡されました。二乗した和を返します。";
 return $n ** 2 + $m ** 2;
}

my $ret = mySub(2, 3, 4);
say "戻り値は $ret でした。";

$ subroutineExample2.pl
Too many arguments for main::mySub at /home/cf/perl/subroutineExample2.pl line 15, near "4)"
Execution of /home/cf/perl/subroutineExample2.pl aborted due to compilation errors.

 なるほど、「main::mySubに対する引数が多すぎる」と怒られてました。狙いどおりですね。

 さて、上のプログラムはmySubというサブルーチン定義をメイン実行部分の先に置いています。Perlはmain()関数などがないので、チェックは上から実行されます。
 ここで、サブルーチン定義を下に回すとどうなるでしょうか。

#! /usr/local/bin/perl
# subroutineExample3.pl -- サブルーチンの実験3

use strict;
use warnings;
use 5.10.0;

my $ret = mySub(2, 3, 4);
say "戻り値は $ret でした。";

sub mySub ($$) {
 my $n = shift;
 my $m = shift;
 say "引数 $n と $m を渡されました。二乗した和を返します。";
 return $n ** 2 + $m ** 2;
}


$ subroutineExample3.pl
main::mySub() called too early to check prototype at /home/cf/perl/subroutineExample3.pl line 8.
引数 2 と 3 を渡されました。二乗した和を返します。
戻り値は 13 でした。

 狙いどおり、今日のお題の警告が表示されました。あと、さっきコンパイルエラーになったプログラムが、警告だけで、実行されています。テンプレートのチェックをせず、引数の数に関わらず実行してしまうことが分かります。これではテンプレートの意味がありません。

 呼び出し側でシジル&を付けるとこうなります。

#! /usr/local/bin/perl
# subroutineExample4.pl -- サブルーチンの実験4

use strict;
use warnings;
use 5.10.0;

my $ret = &mySub(2, 3, 4);
say "戻り値は $ret でした。";

sub mySub ($$) {
 my $n = shift;
 my $m = shift;
 say "引数 $n と $m を渡されました。二乗した和を返します。";
 return $n ** 2 + $m ** 2;
}

$ subroutineExample4.pl
引数 2 と 3 を渡されました。二乗した和を返します。
戻り値は 13 でした。

 警告さえも出なくなりました。
 &を付けて呼び出すとプロトタイプのチェックがなくなります。プロトタイプを付けた関数を下に定義していても警告がなくなり、プロトタイプに違反していても堂々と実行されます。

 やっぱりサブルーチン定義を先頭に持ってきて、シジル&を使わないで呼んだほうがいいのでしょうか。でも、サブルーチン定義は後ろに回したほうが見やすい気もします。
 プロトタイプを使って、引数を多く渡した時はちゃんとコンパイルエラーになって欲しい。でも、関数の宣言は後に回したい。その場合は、プロトタイプ宣言だけ先にやることもできます。

#! /usr/local/bin/perl
# subroutineExample5.pl -- サブルーチンの実験5

use strict;
use warnings;
use 5.10.0;

sub mySub ($$);

my $ret = mySub(2, 3, 4); # シジル&を外した
say "戻り値は $ret でした。";

sub mySub ($$) {
 my $n = shift;
 my $m = shift;
 say "引数 $n と $m を渡されました。二乗した和を返します。";
 return $n ** 2 + $m ** 2;
}

[sample]$ ./subroutineExample5.pl
Too many arguments for main::mySub at ./subroutineExample5.pl line 10, near "4)"
Execution of ./subroutineExample5.pl aborted due to compilation errors.
[sample]$

 ちゃんとコンパイルエラーになりました。一応修正します。

#! /usr/local/bin/perl
# subroutineExample6.pl -- サブルーチンの実験5

use strict;
use warnings;
use 5.10.0;

sub mySub ($$);

my $ret = mySub(2, 3);
say "戻り値は $ret でした。";

sub mySub ($$) {
 my $n = shift;
 my $m = shift;
 say "引数 $n と $m を渡されました。二乗した和を返します。";
 return $n ** 2 + $m ** 2;
}

[sample]$ ./subroutineExample6.pl
引数 2 と 3 を渡されました。二乗した和を返します。
戻り値は 13 でした。
[sample]$