camel

どうやら私の本では、啓蒙が全然足りなかったらしい。

Perl/CGI辞典 - 土井 毅さん 著 - にて use strict が推奨されていない件について - iandeth.
p.104
strict プラグマは、Perlスクリプトでの記法を厳密にするためのプラグマです。 (中略) これにより、宣言の曖昧な変数への参照を発見できます。
[参考] strict プラグマは厳密すぎるため、通常のプログラミングではあまり使用しません。
... orz

この本が20世紀に出たというのであれば驚かないけど、今年に出たというのは、Perl5 Porterとしてもショックである。

しかし、確かにuse strict; # or dieという姿勢だけではなく、use strict; # and be happyという姿勢も必要なのだと思う。

Perl/CGI辞典 - 土井 毅さん 著 - にて use strict が推奨されていない件について - iandeth.
Perl言語をこれから使おうとして、この本を手に取っている人達に対して strictプラグマ を「あまり使いません」と切って捨てちゃ駄目だと思う (悲)。

というわけで、改めてuse strictが何をするのかを、改めて解説します(ここからですます調)。


使い方

これだけです。

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

なにはなくとも#!の直下の行にuse strictと書くだけ。ついでなので、use strictされていないperl scriptを見つけるscriptを以下に。

#!/usr/bin/env perl
use strict;
use warnings;
use Getopt::Std;
use File::Find ();

my %opt;
getopts("v" => \%opt);
push @ARGV, '.' unless @ARGV;

sub check{
    my $path = shift;
    open my $fh, '<', $path or die "$path : $!";
    my $text = do{ local $/; <$fh> };
    close $fh;
    my @ok = ('not strict', 'strict');
    my $ok = $text =~ /^use\s+strict;/m ? 1 : 0;
    print "$path\t: $ok[$ok]\n" if ($opt{v} or !$ok); 
}

sub wanted {
    my ($dev,$ino,$mode,$nlink,$uid,$gid);
    (($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) or return;
    -f _ or return;
    /\w.*\.(?:pl|pm|t)\z/s or return;
    check($File::Find::name);
}

File::Find::find({wanted => \&wanted}, @ARGV);
__END__

何をするか

ここで問題です。以下のプログラムは何をするでしょうか?

#!/usr/local/bin/perl
my $hel1o = "hello, world!";
print $hello, "\n";

答え:ただの空行が出力されます。しかしこれはあなたが期待していた出力でしょうか?

ここで、use strictしてみましょう。

#!/usr/local/bin/perl
use strict;
my $hel1o = "hello, world!";
print $hello, "\n";

今度は、

Global symbol "$hello" requires explicit package name at ...

というメッセージを出して止まったはずです。実は$hel1o$hel1oとなっていて、$helloはどこにも使われていなかったのです。

人の目で見つけるより、perlに見つけさせた方がよくありませんか?strictがそれをやってくれるのです。

必要なときにだけ、no strict 'refs';

どうしてもuse strictでプログラムが動かない場合も、該当箇所だけ選んでその効果を切る事ができます。以下では、ピンクの部分だけ選択的にstrictの影響を切っています。

sub make_instances {
    my ( $pkg, $arg_ref ) = @_;
    croak 'Usage: ' . $pkg . '->new({key => val, ...})'
      unless ref $arg_ref eq 'HASH';
    for my $arg ( keys %$arg_ref ) {
        no strict 'refs';
        *{ $pkg . '::get_' . $arg } = sub($) {
            my $self = shift;
            return $self->{$arg};
          }
          if $arg_ref->{$arg} =~ /r/;
        *{ $pkg . '::set_' . $arg } = sub($$) {
            my $self = shift;
            return $self->{$arg} = shift;
          }
          if $arg_ref->{$arg} =~ /w/;
    }
}

ここでno strict 'refs';となっている点に注目してください。ただのno strict;ではなく。実は、use strict;には、varsrefs、そしてsubsという3種類の効果がありますが、no strict;ではこの三種類の効果を全部殺してしまいます。だから、他を活かしたまま必要なところだけ切るという使い方をするわけです。

実際問題、必要となるのはこのno strict 'refs';だけでしょう。varsはすでにourがあるためほとんど不要ですし、subsは\&subnameという書き方があるため、これもまたほとんど不要です。そしてno strict 'refs';が本当に必要なのは、中級以上のscriptだけです。

まとめ

いかがでしょう?これでもstrictは不要ですか?

本当の友は、あなたのいい点だけではなく、あなたの問題点も指摘してくれるといいます。そういう人こそ友だというあなたは、use strictでよりperlをフレンドリーなものにしてください。

なお、Perl 6では、このstrict(とwarnings)が標準となります。例外は-eをつけて、コマンドラインから実行する場合だけです。


こんなとこかな。

Perl/CGI辞典 - 土井 毅さん 著 - にて use strict が推奨されていない件について - iandeth.
いや、僕が一人で書くのではなくて、ここは Perl 好きなみんなの力を合わせて、共同で「Perl はこんなに便利だよ・楽しいよ」的な初級 - 中級レベルの本を執筆してみませんか?

実は本に関しては、新たな企画が進行中です。もうすぐ発表できると思います。乞うご期待!

Dan the Strict, Friendly Perl Monger