このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。
最後に、新しくモジュールを起こす場合に
便利と思われる機能を考えてみよう。
現行の property モジュールの仕様であれば、
setter/getter の多いモジュールの場合、
それらをプロパティ化するために、
いくつも指定しなければならない。
use property 'name';
use property 'gender';
use property 'weight';
use property 'salary';
方法として、property モジュールの引数を改造し、
複数のプロパティを一度に指定することはできる。
use property qw/name gender weight salary/;
しかし、setter/getter を新たに追加した場合、
property を追加で指定しなければならない。
つまり、setter/getter の修正と、
use property の登録をセットで行なう必要がある。
property は、プラグマ的モジュールであるため、
自動的に暗黙的に作用するのが好ましい。
なので、「二度手間」と感じてしまうのだ。
特に新規で起こすモジュールの設計段階の場合、
設計を修正することは多いため、
property への登録を忘れることも考えられる。
そこで、パッケージのシンボルテーブルを検索し、
set_XXX/get_XXX の名前を持つメソッドを見つけ、
自動的にプロパティを作成する事ができれば便利だ。
例えば、use property; とだけ指定した場合、
上記のような効果があれば便利でないだろうか。
あるクラスを継承した場合、継承されたメソッドは、
継承したクラスのシンボルテーブルには存在しないが、
継承する側のクラスが、それらの存在を知っているため、
それは個別に property 指定をすれば事足りる。
さて、上記を実装する場合、シンボルテーブルから
メソッドだけを検索する必要がある。
シンボルテーブルは連想配列なので、
シンボルテーブルのキーの名前を調べればよさそうだが、
シンボルテーブルには、型グロブが格納されているので、
型グロブのコードスロットに、コードリファレンスが
格納されているかどうか調べる必要がある。
今までは型グロブに対して項目を追加するだけだったため、
型グロブに対するデリファレンス構文を使っていたが、
これはその場で実体が作成されてしまい、うまくいかない。
package Package;
our $value;
package main;
use Data::Dumper;
print Dumper \&{$Package::{'value'}};
以上を実行すると、デリファレンスの時点で実体ができ、
シンボルテーブルに &Package::value が登録されてしまう。
そのため、Dumper は、有効なコードリファレンスを返す。
$VAR1 = sub { "DUMMY" };
勝手に作成されないようにするためには、
型グロブのスロットを参照する必要がある。
これには、これまた専用の構文がある。
型グロブに対して連想配列のようなアクセスをすることで、
各スロットにある、項目のリファレンスを得ることができる。
package Package;
our $value;
package main;
use Data::Dumper;
print Dumper *{$Package::{'value'}}{'CODE'};
以上を実行するとこうなる。
$VAR1 = undef;
つまり、'value' のコードリファレンススロットには
コードが登録されていないということになるのだ。
* を使ってデリファレンスしているのは、
式の優先順位の問題があるからだ。
*{$Package::{'value'}} が型グロブであるため、
その 'CODE' スロットにアクセスすることになる。
つまり、*Package::value{'CODE'} と同じである。
コードスロットは、'CODE' というキーで参照でき、
コードがあればそのリファレンスが返るのだ。
$Package::{'value'}{'CODE'}
もし、以上のように書いてしまうと、
$Package::{'value'}->{'CODE'}
上のように解釈される。これは、
$Package::{'value'} を連想配列としてデリファレンスし、
%Package::value より 'CODE' というキーを参照する。
つまり、$Package::value{'CODE'} のことだ。