Yet another alias module: Scalar::Alias
Lexical::Typesを見て型つきレキシカル宣言の威力を知り,試してみたくなったので一つモジュールを書いてみた。
- Scalar::Alias - search.cpan.org
この型つきレキシカル宣言はうまく使うといろいろ面白いことができそうだ。しかもオーバーヘッドがコンパイル時のみというのがうれしい。
#!perl -w use strict; use Scalar::Alias; sub inc{ my alias $x = shift; $x++; return; } my $i = 0; inc($i); print $i, "\n"; # => 1 __END__
エイリアスを実現するモジュールは既に数多くあるが,このモジュールは高速であることが特徴となっている。これは,PL_peeppハックによってコンパイル済みの構文木を直接変更しており*1,レキシカル変数の参照と代入を独自のopcodeに差し替えていることによる。したがって,コンパイルに余計な時間とメモリを使用する代わり,実行時には余計なコストは掛からない。むしろ,値のコピーを行わない分通常の代入文よりも高速でさえある。
なお,速度については,通常の代入と比較してみた(perl 5.10.0 linux, multi-threaded, -DDEBUGGING)。
For integer Rate assign alias assign 49321/s -- -6% alias 52609/s 7% -- For string Rate assign alias assign 41754/s -- -22% alias 53593/s 28% -- For object reference Rate assign alias assign 42708/s -- -20% alias 53095/s 24% --
対象となる値が整数の場合はあまり変わらないが,それ以外の場合は25%程度高速であるようだ。ただし,この結果はPerlのバイナリによってもかなり差がある。別のバイナリ(5.8.8 linux, multi-threaded)ではこれより差が大きかったが,ここでは差が小さいほうを記しておく。
#!perl -w use strict; use Benchmark qw(:all); use Scalar::Alias; print "For integer\n"; my @integers = ((42) x 100); cmpthese -1 => { alias => sub{ for my $i(@integers){ my alias $x = $i; } }, assign => sub{ for my $i(@integers){ my $x = $i; } }, }; print "For string\n"; my @strings = (('foo') x 100); cmpthese -1 => { alias => sub{ for my $i(@strings){ my alias $x = $i; } }, assign => sub{ for my $i(@strings){ my $x = $i; } }, }; print "For object reference\n"; my @refs = ((bless{}) x 100); cmpthese -1 => { alias => sub{ for my $i(@refs){ my alias $x = $i; } }, assign => sub{ for my $i(@refs){ my $x = $i; } }, }; __END__