Use -w in applications, use warnings in modules
警告のためには -w
ではなく use warnings
を使うべき,という意見がある*1。
しかしそれはある意味では正解だが,ある意味では間違いである。正しくは「アプリケーションでは #!行に-wと書き,モジュールではuse warningsを使う」である。
以下のコードではそれを示す。
(1)
$ perl -MFile::Spec -E 'say File::Spec->join("foo", undef)' foo/ $
(2)
$ perl -MFile::Spec -wE 'say File::Spec->join("foo", undef)' Use of uninitialized value $file in concatenation (.) or string at ... foo/ $
(3)
$ perl -MFile::Spec -E 'use warnings; say File::Spec->join("foo", undef)' foo/ $
(1), (2), (3)の例のうち,あるべき警告が出ているのは(2)の-w
指定のケースのみである。つまり,use warnings
の効果はレキシカルなので,読み込むモジュールにとっては効果がないのだ。そしてFile::Specは内部でuse warnings
を指定していない。
したがって,すべてのモジュールがuse warnings
を指定しているのでなければ安全のために-wを指定したほうがいい,ということになる。
一方モジュールでは,グローバルな状態(-w)に何らかの仮定をするのは望ましくないので,常にuse warnings
を指定したほうがよい。
つまりPerlの警告メカニズムを有効に使うためには,アプリケーションでは #!行に-wと書き,モジュールではuse warningsを使うべき,ということになる。
(追記)
コメントで反対意見をいただいた。要旨としては「モジュール内でuse warningsをしていないのは(1)後方互換性のため,あるいは(2)意図的なポリシーとしてであり,いずれにせよ意図的なものなので,-w
によってその意図を破壊してはならない」ということだと解釈した。以下はその点について反論したい。
私は警告モードについてモジュール製作者の意図を汲む必要はないと考えている。すなわち,(1)の後方互換性のためだとすれば,モジュール作者はメインプログラムで-wが使われることを想定していると考えられるため,アプリケーションでは-wを指定するべきだろう。(2)の意図的なものだとすれば,すべての警告を無視するのではなく,無視したい警告カテゴリに対してno warnings
を使うべきだろうし,そうでないとしても,モジュールの使用者側で警告を回避する方法はあるのが普通だ*2。いずれにしても-wによってその意図が破壊されることはない。
たとえば本文では非常によくつかわれる標準モジュールとしてFile::Specの例をあげたが,File::Specが引数のチェックしないというのは確かにFile::Specのポリシーかもしれない。しかしこれは,-wを前提としたうえで,使用する側が引数をチェックするべきだという意味に他ならない。5.6.0より前は-wを前提にしてプログラムを書くのが普通だったのだから。
また,例ではuninitialized警告を扱ったが,警告はそれだけではない。ある特定の警告がうるさいからといって-wを指定しないのはベストプラクティスとは言えない。