2009年3月15日
Perlのサブルーチンプロトタイプについて
プログラミングPerlとPerlベストプラクティスを読み返して勉強しなおした。概要としてはこんな感じ。
- サブルーチンの引数の型を指定出来るようになる
- 暗黙的にリファレンス渡しができるようになる
例えば、組み込み関数のpushは第一引数に配列を取るが、暗黙的にリファレンス渡しになっている。(引数リストとして展開されない)
このような挙動は通常のPerlのサブルーチンの仕組みでは実現できないが、プロトタイプを使うと実現できる。
sub my_push(\@@){
my ($arr_ref, @arr) = @_;
for(@arr){
$$arr_ref[$#$arr_ref+1] = $_;
}
}
my @test_arr = (1,2,3,4,4);
my_push(@test_arr, 1,2,3);
print join ',',@test_arr; #1,2,3,4,4,1,2,3
ただし、サブルーチンを呼び出す時に&(アンパサンド)をつけるとプロトタイプは無視され、引数指定を無視してもコンパイルエラーにならない。なので、アンパサンドをつけた関数呼び出しは一切しない方が良い。
昔は、自分で定義したサブルーチンは組み込み関数と混同しないように、アンパサンドを付けるのが流儀だったが、今はアンパサンドをつけないのが主流。
その代わり、組み込み関数は括弧無しで呼び出して、ユーザー定義サブルーチンは括弧付きで呼び出すと言うのが流儀。
join ',', @array; #組み込み関数
my_subroutine($hoge, $fuga); #ユーザー定義サブルーチン
そもそも、ファイルハンドルも$付きが推奨されている昨今、コード内に裸のワードは組み込み関数とサブルーチンくらいしか出てこないのである。
open my $fh,'<','hoge.txt';
勿論、自分が定義したサブルーチンを裸のワードで使っていると、将来的に定義された予約語、組み込み関数とバッティングする可能性があるが、そんなサブルーチン名を定義しない or ちゃんとオブジェクト志向モジュールにする、という対策をしておけば問題は起こらない。
しかし、プロトタイプは意図しない挙動をして混乱を招きやすいので使わない方が良い。例えば以下。
sub max($$){
my ($arg1, $arg2) = @_;
return $arg1 > $arg2 ? $arg1 : $arg2;
}
print max(3,5); #5が出力
my @hoge = (3,5);
print max(@hoge); #エラー:Not enough arguments!
no strict 'refs';
と感覚的には同じで、上級者向けって感じかな。例えば、&を使ってサブルーチンリファレンスを引数として持たせると新しい構文を作り出すことが出来て面白い。以下、プログラミングPerl p263より引用。
sub try(&$){ my ($try, $catch) = @_; eval { &$try }; if ($@) { local $_ = $@; &$catch; } } sub catch(&){ $_[0] } #実行 try{ die "phooey"; } catch{ /phooey/ and print "unphooey\n"; };
Perl6では他の言語同様サブルーチンの引数付き宣言も出来るようになるみたいだけど、個人的には従来の引数の指定方法は好き。Perl覚えたての頃は奇妙に思えるけど、そっちの方が引数がその関数ブロックの中のスコープにあると言うことが分かりやすいから。
sub my_sub{
my ($arg1, $arg2) = @_; #$arg1と$arg2が関数内ブロックのスコープにあることが明らか
...
}