FieldHashの使い道
FieldHashを使ったInside-Outクラスあれこれの続き。
結局のところ,FieldHashによるInside-Outクラスはハッシュリファレンスを用いたものより遅い。しかしそれにもかかわらず,FieldHashが非常に有効なケースがある。それは,Mixinクラスを作るときに本来のオブジェクトの実装に影響を与えずにプロパティを設定したいときである。
たとえば,DBIx::Classで使われているClass::Accessor::Grouped(v0.08002)には以下のような箇所がある:
sub get_inherited { my $class; if (Scalar::Util::blessed $_[0]) { my $reftype = Scalar::Util::reftype $_[0]; $class = ref $_[0]; if ($reftype eq 'HASH' && exists $_[0]->{$_[1]}) { return $_[0]->{$_[1]}; } elsif ($reftype ne 'HASH') { Carp::croak('Cannot get inherited value'); }; } else { $class = $_[0]; }; # *snip* }
これはオブジェクトの実体がハッシュリファレンスであることに依存しているが,以下のようにFieldHashを使うとその依存をなくすことができる。
fieldhash my %inherited_of; sub get_inherited { my $class; if (Scalar::Util::blessed $_[0]) { # set_inherited()で$inherited_of{ $_[0] } = {}とする if(my $storage = $inherited_of{ $_[0] }){ return $storage->{$_[1]}; } else { Carp::croak('Cannot get inherited value'); }; } else { $class = $_[0]; }; # *snip* }
FieldHashは実際には任意のリファレンスをキーに取れるので,blessされていないリファレンスに対してプロパティをセットすることさえできる。しかもそのプロパティの実体はリファレンスの外にあるので,他のモジュールのプロパティと衝突することがない。
したがって,FieldHashは独自のプロパティを必要とするMixinやRoleといったコンポーネントモジュールを実装する際には考慮に値する。