camel

最近は、さすがにuse strict;されていない実践コードを目にすることもほとんどなくなってきたのだけど、まだ残っているのがuse warnings;利用。以下と併せて読んでいただけると幸いだ。

-w って何? warnings って何?

まず、以下のプログラムを見てみよう。

#!/usr/local/bin/perl
use strict;

sub distance {
    my ( $a, $b ) = @_;
    return sqrt( $a**2 + $b**2 );
}

print distance(@ARGV), "\n";
% perl scratch.pl 3 4
5

use strict;しているし、そして期待どおりに動いている。

しかし、以下の場合は期待どおりだろうか。

% perl scratch.pl 3
3

distance()は引数を二つ要求するのに、一つしか入れなくても動いてしまう。これは$bundefとなり、数値コンテキストでは0として解釈されるため当然なのだけど、あなたは本当は$bを初期化しておきかったとする。どうすればよいか。

こういう時に活躍するのが、-wスイッチであり、use warnings;である。

まずは-wを見てみよう。

% perl -w d0.pl 3
Use of uninitialized value $b in exponentiation (**) at warnings.pl line 6.
3

確かに"Use of uninitialized value $b"という警告が出た。

次にuse warnings;を見てみよう。

% cat scratch.pl 
#!/usr/local/bin/perl
use strict;
use warnings;

sub distance {
    my ( $a, $b ) = @_;
    return sqrt( $a**2 + $b**2 );
}

print distance(@ARGV), "\n";
% perl scratch.pl 3
Use of uninitialized value $b in exponentiation (**) at warnings.pl line 7.
3

こちらもきちんと警告を出している。

-w だと何がいけないの?

それでは、なぜuse warnings;を使うべきで、-wでないのか。-wの方がuse warnings;より短いではないか。

理由は二つある。

-w.plには有効でも.pmには有効ではない

これが一番の理由である。-wはあくまでも実行時のスイッチなので、スクリプト、すなわち実行ファイルで指定しないと有効にならない。

Distance.pm
package Distance;
use strict;

use base 'Exporter';
our @EXPORT = qw/distance/;

sub distance {
    my ( $a, $b ) = @_;
    return sqrt( $a**2 + $b**2 );
}

1;
scratch.pl
#!/usr/local/bin/perl
use strict;
use Distance;
print distance(@ARGV), "\n";

と別れている場合、-wだと.plの方で指定しないと有効にならないのだ。ところが、use warnings;であれば.pmの方で指定してもきちんと警告してくれるのだ。

no warnings 'whatever';できない

use warnings;ということは、no warnings;も存在するということである。実際これは存在し、かつレキシカルなので、以下のように局所的に警告を止めることも出来る。

sub distance {
    no warnings 'uninitialized';
    my ( $a, $b ) = @_;
    return sqrt( $a**2 + $b**2 );
}

-wでもこれに相当することは不可能ではないが、

sub distance {
    local $^W = undef;
    my ( $a, $b ) = @_;
    return sqrt( $a**2 + $b**2 );
}

という極めて醜いものである。

まとめ

というわけで、今後スクリプトを書く時には、

use strict;
use warnings;

をお忘れなきよう。

モジュールを書くのであれば、

package MyModule;
use strict;
use warnings;

としていただきたい。ちなみにh2xsModule::Starterを使ってモジュールを初期生成した場合、この二行は必ず入っている。あと、Mooseにはこの二行と同等の効果も含まれている。

use warnings; # and be safe!

Dan the Perl Monger

See also: