警告のためには -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を指定しないのはベストプラクティスとは言えない。