cflow系ポイントカットとifポイントカットの相性

この件は、言語仕様として明には書かれていない(と思われる)ため、
違うバージョンでは違う振る舞いをするかもしれません。


ちなみに、実験したバージョンはこんな感じです。

Eclipse 3.3.0(Europa)
AJDT 1.5.0
AspectJ 1.5.4.200705211336
JDK 1.6.0_02


例えば、以下のようなコードがあったとします。

01:public class AspectSample {
02:    public static void main(String[] args) {
03:        foo();
04:        bar();
05:    }
06:    private static void bar() {
07:        foo();
08:    }
09:    private static void foo() {
10:        System.out.println("Call foo.");
11:    }
12:}

そこに、以下のようなアスペクトを定義したとします。

01:public aspect SampleAspect {
02:    public pointcut pc() : 
03:        call(void AspectSample.foo())            //(i)
04:        && cflow(call(void AspectSample.bar()))  //(ii)
05:        && if(isHook())                          //(iii)
06:        ;
07:    static boolean isHook() {
08:        System.out.println("calling isHook");
09:        return true;
10:    }
11:    before() : pc() {
12:        System.out.println("calling foo...");
13:    }
14:}

この状態で、AspectSampleを実行すると標準出力にはいかのように出力されます。

calling isHook
Call foo.
calling isHook
calling foo...
Call foo.

何が嫌って、「calling isHook」が2回表示されてるじゃないですか!


論理積は、論理式を構成する1要素でも偽なら式全体も偽になります。
前方評価であれ、後方評価であれ、真偽値として偽が現れれば以降の
評価は中断したほうが性能はいいのですがAspectJでは、全ての単項目を評価してしまいます。
(i)、(ii)、(iii)の表記順を変えても「calling isHook」はやはり2回表示されてしまいます。
javaのif文では前方評価なので、「if(func1() && func2())」という記述をした場合、
func1がfalseを返すのであれば、func2は呼び出しません。
ifポイントカット内のメソッドでDBにアクセスでもしようものならその性能差は無視できないものになるでしょう。


動的に変化するcflow系とifポイントカットは性能的には一緒くたに使用しないほうがよいみたいです。
cflow系を用いたポイントカットでかつifポイントカットが必要になるような場合は、
アドバイスの中で素直にif文で処理の振り分けをしてあげるほうが、速度的にはGoodと言えるでしょう。


ただ、この問題の対処は実が難しい気がしています。
実装的にと言うよりも、数学的にです。
なぜならば、ポイントカットとは、論理値ではなくジョインポイント集合だからです。
だから、論理積って上で書いたのは適切ではなく、正確には積集合と書くべきなのです。
集合だと考えると、1つ1つの集合がありきであって、集合同士をかけたり足したりは、
その次だと言われればそのような気がしなくもないのです。


とは言え、どっちにしろおいらは素人さんなのでAと言う集合とBと言う集合を積集合した結果、
特定のジョインポイントが対象外ならばCの集合はみなくてもいいじゃんとも思うんですけど、
正味なところどうなんでしょうねぇ。。。