2006 年 4 月 30 日 23 時 15 分

メソッドの存在確認


このアーカイブは同期化されません。 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'} のことだ。



Copyright (c) 1994-2007 Project Loafer. All rights reserved.