open()の改良

Perlのopen()をマスターするのは大変だ。perldoc perlfuncのopenの項はすさまじい長さだし,perldoc perlopentutというopenのチュートリアルも,単なるチュートリアルなにものすごく長い。しかもPerlIOという機能のおかげでopen()そのものも自由に拡張できる。さらに,5.6.0以降の拡張*1が煩雑さに拍車をかけている。
そこで,いくつかの欠点を克服するべく,open()のラッパーを考えてみた*2

use Carp qw(croak);
sub my_open{
	if(@_ < 2){
		croak('Usage: my_open($mode, @args)');
	}
	my $anonio;
	unless(CORE::open $anonio, $_[0], @_[1..$#_]){
		croak("Cannot open(@_): $!");
	}
	return bless $anonio => 'IO::Handle';
}

これは以下のように使用する。

my $in  = my_open('<', 'foo.txt');
my $out = my_open('>', 'foo.txt');
my $tee = my_open('>:tee', 'foo.txt', \$s, \*STDERR);

Perlのopen()と異なる点は以下の通り。

ファイルハンドルをシンボルではなく値として扱う

これはIO::Fileが提供する機能である。しかし後述するように,IO::Fileでは3つ以上の引数が扱えない。

3引数のopen()を強要する

2引数のopen()はファイル名の前に文字列としてモードを付加する。これはこれで便利な機能だが,通常は必要のない機能である。

3つ以上の引数を扱える

サンプルコードの:teeの例のように,Perのopen()は3つ以上の引数を受け付ける可能性がある。しかし,IO::Fileのnew()は透過的にsysopen()を使えるかわりに,3つ以上の引数のopen()を扱えない。

open()に失敗したときに致命的エラーを発生させる

open or dieというイディオムの必要がない。標準モジュールのFatalでも同様の機能を期待できるが,Fatalモジュールが作り出すopen()は3つ以上の引数を扱えない。
FatalやIO::Fileといった標準モジュールで3つ以上の引数のopen()の存在が無視されているのはなんとも悲しい。もっとも使う機会はきわめて稀だとは思うが。

*1:3引数のopen()とファイルハンドルの自動生成

*2:PerlIO::Utilはこのmy_open()と同じものを提供している