一日ズレてしまったが、Perlのエラーメッセージのコーナー。
2週間に一度、水曜日は、Perlのエラーメッセージが表示される最小のプログラムを書いて、どういうときにどう怒られるかを研究する。
今回は
%s() called too early to check prototype
である。

これは例によって、

(主語S):%s()
(動詞V):(was)
(補語C):called too early to check prototype

というbe動詞が省かれた受動態の文で?

(主語S):%s()
(動詞V):は
(補語C):プロトタイプをチェックするには早すぎて呼ばれた

ということで、
%s()を呼び出すのが早すぎるので、プロトタイプのチェックができない
という訳になる。
プロトタイプとは何か。
これは、関数で引数の型を宣言するものだ。
Perlでは引数が全部@_という特殊変数に入ってサブルーチンが呼ばれる。
このために、サブルーチンの引数が何個であるかを明示する必要はない。
また、Perlの変数は型がないので、型宣言も必要ない。
(出来ない。)
しかも@_は呼び出し側と呼び出され側でメモリ空間を共有する。
これは、非常にPerlの緩いところである。

ここに、あえて人為的な制限を加えるのがプロトタイプ宣言である。
以下のプログラムでは、サブルーチンmySubに、$$というプロトタイプを書くことで、スカラー2個を渡されることが明らかになっている。
まず正常に呼んでみる。
#! /usr/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 でした。
べつにどうってことないプログラムである。
さて、これをプロトタイプを無視して、引数を3個渡してみよう。
#! /usr/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, 4);
say "戻り値は $ret でした。";
実行してみる。
$ subroutineExample.pl
Too many arguments for main::mySub at /home/cf/perl/subroutineExample.pl line 15, near "4)"
Execution of /home/cf/perl/subroutineExample.pl aborted due to compilation errors.

なるほどー。
「main::mySubに対する引数が多すぎる」と怒られている。
狙いどおりだ。

さて、上のプログラムはmySubというサブルーチン定義をメイン実行部分の先に置いている。
Perlはmain()関数などがないので、特定のサブルーチンではない部分を上から実行していく。
しかし、見づらい。
サブルーチン定義を下に回すとどうなるであろうか。
#! /usr/bin/perl
# subroutineExample.pl -- サブルーチンの実験

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;
}
実行してみる。
$ subroutineExample.pl
main::mySub() called too early to check prototype at /home/cf/perl/subroutineExample.pl line 8.
引数 2 と 3 を渡されました。二乗した和を返します。
戻り値は 13 でした。
なるほどー。
狙いどおり、今日のお題の警告が表示された。
%s()はサブルーチン名であったことが分かる。

あと、さっきコンパイルエラーになったプログラムが、警告だけで、実行されている。
テンプレートのチェックが出来なかったからできないで、引数の数に関わらず実行してしまうことが分かる。

ではどうするか。
呼び出し側でシジル&を付けるというのもある。
#! /usr/bin/perl
# subroutineExample.pl -- サブルーチンの実験

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;
}

これだとどうなるか。

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

&を付けて呼び出すとプロトタイプのチェックがなくなる。
プロトタイプを付けた関数を下に定義していても警告がなくなり、プロトタイプに違反していても堂々と実行される。
スッキリするが、プロトタイプの機能が使えないので不便な気もする。

サブルーチン定義を上に持ってきてもいいし、別ファイルのモジュール(~.pm)に括り出してuseするのも一方だ。

Toyota Prototype