no warnings 'uninitialized'なんてしちゃいけません
ストロング弾が変なことを言うのはいつものことですが、こいつは著書でtaintチェックしろと言う人の言葉とは思えませんなあ。
no warnings 'uninitialized';
これが一番基本的な対策になります。
こういうのは対策とは言いません。こんなことをするくらいなら最初からuse warningsしない方がましです。perl 5.6以前の世界になりますが、これはDamianセンセもPerl Best Practicesの中で認めていること。日本語版は持っていないので英語版から引っ張ってくると(p.432)
Note that it may still be appropriate to comment out the use warnings line when your application or module is deployed, especially if non-technical users will interact with it...
no warningsが意味を持つのは、たとえばこういう場合。
package Suppress::Redefined::Warnings; use strict; use warnings; require Dan::Kogai; sub reload_dan_kogai { delete $INC{'Dan/Kogai.pm'}; BEGIN { no warnings 'redefine'; require Dan::Kogai; } }
Dan::Kogaiの中身はどうでもいいとして、古くなったDan::Kogaiを一度捨てて再読込したいときなど、そのままだと Subroutine ... redefined at Dan/Kogai.pm という警告が出るので再読込の警告だけオフにするというもの。同種のno strict 'refs'はもうおなじみでしょう。これは明示的に初期化コードを書くというレベルでは対処できないのでno warningsする価値がある。no warnings 'uninitialized'は明示的に(もっと少ないタイプ数で書けるかもしれない)初期化コードを書けば済む話だから意味がない。
次。
my $arg = shift || default_value
(中略)
ただし、この手法には一つ問題があって、明示的に''や0を有効な値としたい場合までデフォルト値で書き得られてしまうのです。これを防ぐには
sub foo{ my ($required, $optional) = @_: $optional = 42 unless defined $optional; }としなければならないくて、||=を使う方法より面倒です。
ついでにundefも有効な値としたい場合はこんな感じですかね。もちろん最初から@_の大きさで分岐させてもいいですが。
sub foo { my $required = shift; my $optional = @_ ? shift : 42;
もうひとつ。
引数にHashを使う
sub foo{ my %arg = ( optional => 42, @_, # ここがポイント ); }
Performanceとか、タイプ数が増えることより、このコードの弱点は間違ってハッシュ以外のものを渡したときの対策がないこと。Odd number of elements in hash assignmentという警告は出ますし、規約重要ということにしておけばよい話ですが、慎重を期すなら
sub foo{ die "foo needs hash" if @_ % 2; my %arg = ( optional => 42, @_, # ここがポイント ); }
のような対策を入れておきたいところですな。