アスペクト指向プログラミング に 関する十の神話

50
1 アアアアアアアアアアアアアア アアアアアアア アアアア ([email protected]) アアアア アアア アアアアアアア = AOP (A spect-O riented P rogramming) ア 37 アアアアアアアアアアアアア 2004 ア 9 ア

Upload: shalin

Post on 31-Jan-2016

66 views

Category:

Documents


0 download

DESCRIPTION

= AOP ( A spect- O riented P rogramming). アスペクト指向プログラミング に 関する十の神話. 増原英彦 ([email protected]) 東京大学 大学院 総合文化研究科. 第 37 回情報科学若手の会招待講演 2004 年 9 月. 概要. AOP 入門 モジュール化の意義 モジュール化のための既存の技術 既存の技術の限界 ―― 横断的関心事 AOP と AspectJ の基本機能 ポイントカット・アドバイス機構 型間宣言機構 神話. お母さんのための AOP 入門. - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: アスペクト指向プログラミング に 関する十の神話

1

アスペクト指向プログラミングに

関する十の神話

増原英彦 ([email protected])

東京大学 大学院 総合文化研究科

= AOP (Aspect-Oriented Programming)

第 37 回情報科学若手の会招待講演 2004 年 9 月

Page 2: アスペクト指向プログラミング に 関する十の神話

2

概要• AOP 入門

– モジュール化の意義– モジュール化のための既存の技術– 既存の技術の限界 ―― 横断的関心事– AOP と AspectJ の基本機能

• ポイントカット・アドバイス機構• 型間宣言機構

• 神話

Page 3: アスペクト指向プログラミング に 関する十の神話

3

お母さんのための AOP 入門

料理のレシピに見る横断的関心事

Page 4: アスペクト指向プログラミング に 関する十の神話

4

プログラムとはレシピのようなものだ

• 両者とも「どのような順序でどのような操作を行うか」を

記述材料 (4 人分 ): 牛肉 300g ・サラダ油大さじ 2 ・じゃがいも

4 個・人参 1 本・玉葱 1 個・ベイリーフ 1 枚・水 5 カップ・バター大さじ 2 ・カレールー 1 箱

1. 牛肉を一口大に切り、サラダ油を熱した鍋で炒める2. 1 に一口大に切ったじゃがいも、人参を加えて炒める3. 玉葱をみじん切りにして、バターを熱したフライパンで

炒める4. 1 に 2 を合わせ、ベイリーフ、水を加えて 30 分煮込む5. アクをとり、カレールーを加えてさらに 20 分煮込む

材料 (4 人分 ): 牛肉 300g ・サラダ油大さじ 2 ・じゃがいも4 個・人参 1 本・玉葱 1 個・ベイリーフ 1 枚・水 5 カップ・バター大さじ 2 ・カレールー 1 箱

1. 牛肉を一口大に切り、サラダ油を熱した鍋で炒める2. 1 に一口大に切ったじゃがいも、人参を加えて炒める3. 玉葱をみじん切りにして、バターを熱したフライパンで

炒める4. 1 に 2 を合わせ、ベイリーフ、水を加えて 30 分煮込む5. アクをとり、カレールーを加えてさらに 20 分煮込む

ビーフカレーの作り方

Page 5: アスペクト指向プログラミング に 関する十の神話

5

1. 1 に一口大に切ったじゃがいも、人参を2. 玉葱をみじん切りにして、バターを熱した3. 1 に 2 を合わせ、ベイリーフ、水を加えて 30

4. アクをとり、カレールーを加えてさらに 20 分

1. 1 に一口大に切ったじゃがいも、人参を2. 玉葱をみじん切りにして、バターを熱した3. 1 に 2 を合わせ、ベイリーフ、水を加えて 30

4. アクをとり、カレールーを加えてさらに 20 分

レシピはモジュール化されてる !

void 皮をむく ( 材料 ) {

switch( 材料 ) {

case 玉葱 : 茶色の薄皮を手でむく

case 人参 : ピーラーを使って… } }

void 皮をむく ( 材料 ) {

switch( 材料 ) {

case 玉葱 : 茶色の薄皮を手でむく

case 人参 : ピーラーを使って… } }

モジュール化 = 一連の手順に名前を付け、別に定義すること

• 使用側では手順の詳細を気にしなくてよ

い• 定義側を独立して変更できる• 同じ手順が何度も出現する

場合に定義を共有できる ― 変更も 1 回

void みじん切り ( 材料 ) {

1. 材料の皮をむく2. for a in X,Y,Z

材料を a 軸方向に 4 ~5mm 間隔に包丁で切る }

void みじん切り ( 材料 ) {

1. 材料の皮をむく2. for a in X,Y,Z

材料を a 軸方向に 4 ~5mm 間隔に包丁で切る }

「決定版 はじめての料理」

Page 6: アスペクト指向プログラミング に 関する十の神話

6

7. 1 に一口大に切ったじゃがいも、人参を8. にんにくをみじん切りにして、バターを熱した9. 1 に 2 を合わせ、ベイリーフ、水を加えて 30

10. アクをとり、カレールーを加えてさらに 20 分

7. 1 に一口大に切ったじゃがいも、人参を8. にんにくをみじん切りにして、バターを熱した9. 1 に 2 を合わせ、ベイリーフ、水を加えて 30

10. アクをとり、カレールーを加えてさらに 20 分1. 1 に一口大に切ったじゃがいも、人参を2. 玉葱をみじん切りにして、バターを熱した3. 1 に 2 を合わせ、ベイリーフ、水を加えて 30

4. アクをとり、カレールーを加えてさらに 20 分

1. 1 に一口大に切ったじゃがいも、人参を2. 玉葱をみじん切りにして、バターを熱した3. 1 に 2 を合わせ、ベイリーフ、水を加えて 30

4. アクをとり、カレールーを加えてさらに 20 分

「みじん切り」の効用モジュール化 = 一連の手順に

名前を付け、別に定義すること

• 使用側では手順の詳細を気にしなくてよ

い• 定義側を独立して変更できる• 同じ手順が何度も出現する

場合に定義を共有できる ― 変更も 1 回

void みじん切り ( 材料 ) {

1. 材料の皮をむく2. for a in X,Y,Z

材料を a 軸方向に 4 ~5mm 間隔に包丁で切る }

void みじん切り ( 材料 ) {

1. 材料の皮をむく2. for a in X,Y,Z

材料を a 軸方向に 4 ~5mm 間隔に包丁で切る }

「決定版 はじめての料理」

Page 7: アスペクト指向プログラミング に 関する十の神話

7

1. 1 に一口大に切ったじゃがいも、人参を2. 玉葱をみじん切りにして、バターを熱した3. 1 に 2 を合わせ、ベイリーフ、水を加えて 30

4. アクをとり、カレールーを加えてさらに 20 分

1. 1 に一口大に切ったじゃがいも、人参を2. 玉葱をみじん切りにして、バターを熱した3. 1 に 2 を合わせ、ベイリーフ、水を加えて 30

4. アクをとり、カレールーを加えてさらに 20 分

「みじん切り」の効用モジュール化 = 一連の手順に

名前を付け、別に定義すること

• 使用側では手順の詳細を気にしなくてよ

い• 定義側を独立して変更できる• 同じ手順が何度も出現する

場合に定義を共有できる ― 変更も 1 回

void みじん切り ( 材料 ) {

1. 材料の皮をむく2. for a in X,Y,Z

材料を a 軸方向に 4 ~5mm 間隔に包丁で切る }

void みじん切り ( 材料 ) {

1. 材料の皮をむく2. for a in X,Y,Z

材料を a 軸方向に 4 ~5mm 間隔に包丁で切る }

「決定版 はじめての料理」

void みじん切り ( 材料 ) {

1. 材料の皮をむく2. 材料をぶつ切りにし

てミキサーで混ぜる }

void みじん切り ( 材料 ) {

1. 材料の皮をむく2. 材料をぶつ切りにし

てミキサーで混ぜる }

Page 8: アスペクト指向プログラミング に 関する十の神話

8

横断的関心事とは「本格派」のようなもの

• 関心事 = ひとまとまりと考えられる手順・材料群・コツ・ etc.

( モジュール = 関心事をひとまとめに記述したもの )

• 横断的関心事 = モジュールに分けて書いたときに、複数のモジュールにまたがる関心事– その関心事は散在してしまう– 他の関心事はもつれてしまう

Page 9: アスペクト指向プログラミング に 関する十の神話

9

横断的関心事とは「本格派」のようなもの

材料 (4 人分 ): 牛肉 300g ・サラダ油大さじ 2 ・じゃがいも 4 個・人参 1 本・玉葱 1 個・ベイリーフ 1 枚・水 5 カップ・バター大さじ 2 ・カレールー 1 箱・カレー粉大さじ 3 ・トマトジュース200cc ・ヨーグルト 1 カップ・ガラムマサラ適量・ブイヨン 3個

1. 牛肉を一口大に切り、カレー粉小さじ 1 と一緒にサラダ油を熱した鍋で炒める

2. 1 に一口大に切ったじゃがいも、人参を加えて炒める3. 玉葱をみじん切りにして、バターを熱したフライパンで炒める4. 1 に 2 を合わせ、ベイリーフ、水、ブイヨン、トマトジュース

を加えて 30 分煮込む5. アクをとり、カレールー残りのカレー粉を加えてさらに 20 分

煮込む6. 仕上げにヨーグルト 1 カップを加え混ぜ、ガラムマサラをかけ

材料 (4 人分 ): 牛肉 300g ・サラダ油大さじ 2 ・じゃがいも 4 個・人参 1 本・玉葱 1 個・ベイリーフ 1 枚・水 5 カップ・バター大さじ 2 ・カレールー 1 箱・カレー粉大さじ 3 ・トマトジュース200cc ・ヨーグルト 1 カップ・ガラムマサラ適量・ブイヨン 3個

1. 牛肉を一口大に切り、カレー粉小さじ 1 と一緒にサラダ油を熱した鍋で炒める

2. 1 に一口大に切ったじゃがいも、人参を加えて炒める3. 玉葱をみじん切りにして、バターを熱したフライパンで炒める4. 1 に 2 を合わせ、ベイリーフ、水、ブイヨン、トマトジュース

を加えて 30 分煮込む5. アクをとり、カレールー残りのカレー粉を加えてさらに 20 分

煮込む6. 仕上げにヨーグルト 1 カップを加え混ぜ、ガラムマサラをかけ

本格派ビーフカレーの作り方

void 玉葱を炒める () {

1. 弱火のフライパンでバターを溶かす

2. while (20 分過つまで飴茶色になるま

で ) 玉葱をかき混ぜる焦げそうになったときはフライパンを火から離し火力を調節する }

void 玉葱を炒める () {

1. 弱火のフライパンでバターを溶かす

2. while (20 分過つまで飴茶色になるま

で ) 玉葱をかき混ぜる焦げそうになったときはフライパンを火から離し火力を調節する }

普通のレシピ

普通のレシピ

Page 10: アスペクト指向プログラミング に 関する十の神話

10

横断的関心事とは「本格派」のようなもの

材料 (4 人分 ): 牛肉 300g ・サラダ油大さじ 2 ・じゃがいも 4 個・人参 1 本・玉葱 1 個・ベイリーフ 1 枚・水 5 カップ・バター大さじ 2 ・カレールー 1 箱・カレー粉大さじ 3 ・トマトジュース200cc ・ヨーグルト 1 カップ・ガラムマサラ適量・ブイヨン 3個

1. 牛肉を一口大に切り、カレー粉小さじ 1 と一緒にサラダ油を熱した鍋で炒める

2. 1 に一口大に切ったじゃがいも、人参を加えて炒める3. 玉葱をみじん切りにして、バターを熱したフライパンで炒める4. 1 に 2 を合わせ、ベイリーフ、水、ブイヨン、トマトジュース

を加えて 30 分煮込む5. アクをとり、カレールー残りのカレー粉を加えてさらに 20 分

煮込む6. 仕上げにヨーグルト 1 カップを加え混ぜ、ガラムマサラをかけ

材料 (4 人分 ): 牛肉 300g ・サラダ油大さじ 2 ・じゃがいも 4 個・人参 1 本・玉葱 1 個・ベイリーフ 1 枚・水 5 カップ・バター大さじ 2 ・カレールー 1 箱・カレー粉大さじ 3 ・トマトジュース200cc ・ヨーグルト 1 カップ・ガラムマサラ適量・ブイヨン 3個

1. 牛肉を一口大に切り、カレー粉小さじ 1 と一緒にサラダ油を熱した鍋で炒める

2. 1 に一口大に切ったじゃがいも、人参を加えて炒める3. 玉葱をみじん切りにして、バターを熱したフライパンで炒める4. 1 に 2 を合わせ、ベイリーフ、水、ブイヨン、トマトジュース

を加えて 30 分煮込む5. アクをとり、カレールー残りのカレー粉を加えてさらに 20 分

煮込む6. 仕上げにヨーグルト 1 カップを加え混ぜ、ガラムマサラをかけ

本格派ビーフカレーの作り方

void 玉葱を炒める () {

1. 弱火のフライパンでバターを溶かす

2. while (20 分過つまで飴茶色になるま

で ) 玉葱をかき混ぜる焦げそうになったときはフライパンを火から離し火力を調節する }

void 玉葱を炒める () {

1. 弱火のフライパンでバターを溶かす

2. while (20 分過つまで飴茶色になるま

で ) 玉葱をかき混ぜる焦げそうになったときはフライパンを火から離し火力を調節する }

•散在•もつれ•散在•もつれ

Page 11: アスペクト指向プログラミング に 関する十の神話

11

材料 (4 人分 ): 牛肉 300g ・サラダ油大さじ 2 ・じゃがいも 4 個・人参1 本・玉葱 1 個・ベイリーフ 1 枚・水 5 カップ・バター大さじ 2 ・カレールー 1 箱

1. 牛肉を一口大に切り、サラダ油を熱した鍋で炒める2. 1 に一口大に切ったじゃがいも、人参を加えて炒める3. 玉葱をみじん切りにして、バターを熱したフライパンで炒める4. 1 に 2 を合わせ、ベイリーフ、水を加えて 30 分煮込む5. アクをとり、カレールーを加えてさらに 20 分煮込む

材料 (4 人分 ): 牛肉 300g ・サラダ油大さじ 2 ・じゃがいも 4 個・人参1 本・玉葱 1 個・ベイリーフ 1 枚・水 5 カップ・バター大さじ 2 ・カレールー 1 箱

1. 牛肉を一口大に切り、サラダ油を熱した鍋で炒める2. 1 に一口大に切ったじゃがいも、人参を加えて炒める3. 玉葱をみじん切りにして、バターを熱したフライパンで炒める4. 1 に 2 を合わせ、ベイリーフ、水を加えて 30 分煮込む5. アクをとり、カレールーを加えてさらに 20 分煮込む

ビーフカレーの作り方

AOP とは「本格派」を分けて書く技術

メリット• 「普通のレシピ」と共存• 「本格派」を別レシピに

再利用

本格派の場合• カレールーのかわりにカレー

粉大さじ 3 を使う• 牛肉はカレー粉大さじ 1 を加

えて炒める• 玉葱を炒めるときは、飴茶色

になるまでじっくりと。焦げそうになったときはフライパンを火から離し火力を調節する

• 具を煮込む際に、ブイヨン 3個とトマトジュース 200cc を加える

• 仕上げにヨーグルト 1 カップを加え、ガラムマサラをかける

本格派の場合• カレールーのかわりにカレー

粉大さじ 3 を使う• 牛肉はカレー粉大さじ 1 を加

えて炒める• 玉葱を炒めるときは、飴茶色

になるまでじっくりと。焦げそうになったときはフライパンを火から離し火力を調節する

• 具を煮込む際に、ブイヨン 3個とトマトジュース 200cc を加える

• 仕上げにヨーグルト 1 カップを加え、ガラムマサラをかける

材料 (4 人分 ): 牛肉 300g ・サラダ油大さじ 2 ・じゃがいも 4 個・人参1 本・玉葱 1 個・ベイリーフ 1 枚・水 5 カップ・バター大さじ 2 ・カレールー 1 箱

1. 牛肉を一口大に切り、サラダ油を熱した鍋で炒める2. 1 に一口大に切ったじゃがいも、人参を加えて炒める3. 玉葱をみじん切りにして、バターを熱したフライパンで炒める4. 1 に 2 を合わせ、ベイリーフ、水を加えて 30 分煮込む5. アクをとり、カレールーを加えてさらに 20 分煮込む

材料 (4 人分 ): 牛肉 300g ・サラダ油大さじ 2 ・じゃがいも 4 個・人参1 本・玉葱 1 個・ベイリーフ 1 枚・水 5 カップ・バター大さじ 2 ・カレールー 1 箱

1. 牛肉を一口大に切り、サラダ油を熱した鍋で炒める2. 1 に一口大に切ったじゃがいも、人参を加えて炒める3. 玉葱をみじん切りにして、バターを熱したフライパンで炒める4. 1 に 2 を合わせ、ベイリーフ、水を加えて 30 分煮込む5. アクをとり、カレールーを加えてさらに 20 分煮込む

野菜カレーの作り方 材料 (4 人分 ): 牛肉 300g ・サラダ油大さじ 2 ・じゃがいも 4 個・人参1 本・玉葱 1 個・ベイリーフ 1 枚・水 5 カップ・バター大さじ 2 ・カレールー 1 箱

1. 牛肉を一口大に切り、サラダ油を熱した鍋で炒める2. 1 に一口大に切ったじゃがいも、人参を加えて炒める3. 玉葱をみじん切りにして、バターを熱したフライパンで炒める4. 1 に 2 を合わせ、ベイリーフ、水を加えて 30 分煮込む5. アクをとり、カレールーを加えてさらに 20 分煮込む

材料 (4 人分 ): 牛肉 300g ・サラダ油大さじ 2 ・じゃがいも 4 個・人参1 本・玉葱 1 個・ベイリーフ 1 枚・水 5 カップ・バター大さじ 2 ・カレールー 1 箱

1. 牛肉を一口大に切り、サラダ油を熱した鍋で炒める2. 1 に一口大に切ったじゃがいも、人参を加えて炒める3. 玉葱をみじん切りにして、バターを熱したフライパンで炒める4. 1 に 2 を合わせ、ベイリーフ、水を加えて 30 分煮込む5. アクをとり、カレールーを加えてさらに 20 分煮込む

マトンマトンカレーの作り方

時間のない場合• 玉葱も一口大に切り、他の野

菜と一緒に炒める• 炒め終わったら圧力鍋で 5 分

間煮る

時間のない場合• 玉葱も一口大に切り、他の野

菜と一緒に炒める• 炒め終わったら圧力鍋で 5 分

間煮る

Page 12: アスペクト指向プログラミング に 関する十の神話

12

以上、お母さんのための AOP 入門

― 本題―プログラミング言語では ?

Page 13: アスペクト指向プログラミング に 関する十の神話

13

プログラミング言語における

モジュール化とは何か ?

• 1 まとめ → 使う側は細部を忘れることができる

• インターフェース ( 型・仕様・etc.)← 「使う側」に対する約束→ 「中身」を「使う側」と

独立して変更できる

「 1 つ」の操作や値を 1 まとめにしてインターフェースを決めること

「 1 つ」の操作や値を 1 まとめにしてインターフェースを決めること

Page 14: アスペクト指向プログラミング に 関する十の神話

14

モジュール化のための技術対象 技術操作 サブルーチン・関数・手続き値 構造体・レコード操作と値 抽象データ型・クラス・

structure

モジュール コンポーネント・ functor

Page 15: アスペクト指向プログラミング に 関する十の神話

16

モジュール化の例 (OOP)

• 図形エディタ [Kiczales, et al. 2001]

– 特徴 : Illustrator のようなもの• 「点」「線」「円」などの部品単位で描画・操

作できる• 対話的な描画―移動すると再描画

• モジュール化の方針– 図形要素をクラスに– 「移動」「描画」等の操作をメソッドに

Page 16: アスペクト指向プログラミング に 関する十の神話

17

モジュール化の例 (OOP)

class Point extends FigElm { int x, y; int getX() { return x; } int getY() { … } void moveby(int dx, int dy) { x+=dx; y+=dy; Display.redraw(); } void setX(int x) { this.x = x; Display.redraw(); } void setY(int y) { … } void draw(Display d) { … } }

class Point extends FigElm { int x, y; int getX() { return x; } int getY() { … } void moveby(int dx, int dy) { x+=dx; y+=dy; Display.redraw(); } void setX(int x) { this.x = x; Display.redraw(); } void setY(int y) { … } void draw(Display d) { … } }

class Line extends FigElm { Point p1, p2; Point getP1() { return p1; } Point getP2() { … } void moveby(int dx, int dy) { p1.moveby(dx,dy); p2.moveby(dx,dy); Display.redraw(); } void setP1(Point p1) { this.p1 = p1; Display.redraw(); } void setP2(Point p2) { … } void draw(Display d) { … } }

class Line extends FigElm { Point p1, p2; Point getP1() { return p1; } Point getP2() { … } void moveby(int dx, int dy) { p1.moveby(dx,dy); p2.moveby(dx,dy); Display.redraw(); } void setP1(Point p1) { this.p1 = p1; Display.redraw(); } void setP2(Point p2) { … } void draw(Display d) { … } }

class FigElm { void moveby(int dx, int dy); void display(Display d); }

class FigElm { void moveby(int dx, int dy); void display(Display d); }

class Display { static List<FigElm> figures = …; static void redraw() {display.draw();} void draw() { for (fig : figures) fig.draw(d); } }

class Display { static List<FigElm> figures = …; static void redraw() {display.draw();} void draw() { for (fig : figures) fig.draw(d); } }

• 図形エディタ

「線」の内部表現と使い方を分離

図形の形による• 違いを隠す• 共通する性質を

まとめる

複雑なデータを 1 つの値として扱える

Page 17: アスペクト指向プログラミング に 関する十の神話

18

Q: 横断的関心事は何 ?

class Point extends FigElm { int x, y; int getX() { return x; } int getY() { … } void moveby(int dx, int dy) { x+=dx; y+=dy; Display.redraw(); } void setX(int x) { this.x = x; Display.redraw(); } void setY(int y) { … } void draw(Display d) { … } }

class Point extends FigElm { int x, y; int getX() { return x; } int getY() { … } void moveby(int dx, int dy) { x+=dx; y+=dy; Display.redraw(); } void setX(int x) { this.x = x; Display.redraw(); } void setY(int y) { … } void draw(Display d) { … } }

class Line extends FigElm { Point p1, p2; Point getP1() { return p1; } Point getP2() { … } void moveby(int dx, int dy) { p1.moveby(dx,dy); p2.moveby(dx,dy); Display.redraw(); } void setP1(Point p1) { this.p1 = p1; Display.redraw(); } void setP2(Point p2) { … } void draw(Display d) { … } }

class Line extends FigElm { Point p1, p2; Point getP1() { return p1; } Point getP2() { … } void moveby(int dx, int dy) { p1.moveby(dx,dy); p2.moveby(dx,dy); Display.redraw(); } void setP1(Point p1) { this.p1 = p1; Display.redraw(); } void setP2(Point p2) { … } void draw(Display d) { … } }

class FigElm { void moveby(int dx, int dy); void display(Display d); }

class FigElm { void moveby(int dx, int dy); void display(Display d); }

class Display { static List<FigElm> figures = …; static void redraw() {display.draw();} void draw() { for (fig : figures) fig.draw(d); } }

class Display { static List<FigElm> figures = …; static void redraw() {display.draw();} void draw() { for (fig : figures) fig.draw(d); } }

• 図形エディタ

Page 18: アスペクト指向プログラミング に 関する十の神話

19

A:図形が変化する度に再描画

class Point extends FigElm { int x, y; int getX() { return x; } int getY() { … } void moveby(int dx, int dy) { x+=dx; y+=dy; Display.redraw(); } void setX(int x) { this.x = x; Display.redraw(); } void setY(int y) { … } }

class Point extends FigElm { int x, y; int getX() { return x; } int getY() { … } void moveby(int dx, int dy) { x+=dx; y+=dy; Display.redraw(); } void setX(int x) { this.x = x; Display.redraw(); } void setY(int y) { … } }

class Line extends FigElm { Point p1, p2; Point getP1() { return p1; } Point getP2() { … } void moveby(int dx, int dy) { p1.moveby(dx,dy); p2.moveby(dx,dy); Display.redraw(); } void setP1(Point p1) { this.p1 = p1; Display.redraw(); } void setP2(Point p2) { … } }

class Line extends FigElm { Point p1, p2; Point getP1() { return p1; } Point getP2() { … } void moveby(int dx, int dy) { p1.moveby(dx,dy); p2.moveby(dx,dy); Display.redraw(); } void setP1(Point p1) { this.p1 = p1; Display.redraw(); } void setP2(Point p2) { … } }

class FigElm { void moveby(int dx, int dy); void display(Display d); }

class FigElm { void moveby(int dx, int dy); void display(Display d); }

class Display { static List<FigElm> figures = …; static void redraw() { … } }

class Display { static List<FigElm> figures = …; static void redraw() { … } }

縺れ• 抽象図形として

利用するときに邪魔

散在• 再描画の

方針変更時に変更箇所が沢山

Page 19: アスペクト指向プログラミング に 関する十の神話

21

アスペクト指向プログラミング (AOP)

• 横断的関心事をモジュール化する技術 [Kiczales+97]

複数のモジュールにまたがる操作や構造の記述手段

• 具体的な処理系 :AspectJ [Kiczales+01], 他多数

• 典型的応用 :ログ・デバグ・最適化・セキュリティ等のモジュール化

Page 20: アスペクト指向プログラミング に 関する十の神話

22

AspectJ 入門 : 適用結果

class Point extends FigElm { int x, y; int getX() { return x; } int getY() { … } void moveby(int dx, int dy) { x+=dx; y+=dy; } void setX(int x) { this.x = x; } void setY(int y) { … }}

class Point extends FigElm { int x, y; int getX() { return x; } int getY() { … } void moveby(int dx, int dy) { x+=dx; y+=dy; } void setX(int x) { this.x = x; } void setY(int y) { … }}

class Line extends FigElm { Point p1, p2; Point getP1() { return p1; } Point getP2() { … } void moveby(int dx, int dy) { p1.moveby(dx,dy); p2.moveby(dx,dy);} void setP1(Point p1) { this.p1 = p1; } void setP2(Point p2) { … } }

class Line extends FigElm { Point p1, p2; Point getP1() { return p1; } Point getP2() { … } void moveby(int dx, int dy) { p1.moveby(dx,dy); p2.moveby(dx,dy);} void setP1(Point p1) { this.p1 = p1; } void setP2(Point p2) { … } }

class FigElm { void moveby(int dx, int dy);}class FigElm { void moveby(int dx, int dy);}

class Display { static List<FigElm> figures = …; static void redraw() {display.draw();} void draw() { for (fig : figures) fig.draw(d); } }

class Display { static List<FigElm> figures = …; static void redraw() {display.draw();} void draw() { for (fig : figures) fig.draw(d); } }

• 図形エディタ

aspect DisplayUpdating { pointcut move() : call(int FigElm.moveby(int,int)) || call(void Point.setX(int)) || call(void Point.setY(int)) || call(void Line.setP1(Point)) || call(void Line.setP2(Point)); after() : move() { Display.redraw(); }

void FigElm.draw(Display d); void Point.draw(Display d) { … } … }

aspect DisplayUpdating { pointcut move() : call(int FigElm.moveby(int,int)) || call(void Point.setX(int)) || call(void Point.setY(int)) || call(void Line.setP1(Point)) || call(void Line.setP2(Point)); after() : move() { Display.redraw(); }

void FigElm.draw(Display d); void Point.draw(Display d) { … } … }

図形が変化する度に再描画する“アスペクト”描画方針と独立

Page 21: アスペクト指向プログラミング に 関する十の神話

23

AspectJ の主要概念• アスペクト (cf. クラス )

横断的関心事をまとめる単位• アドバイス (cf. メソッド )

追加的な操作• ポイントカット (cf. シグネチャ )

適用時点を決める• 型間定義 追加的宣言

動作

構造

Page 22: アスペクト指向プログラミング に 関する十の神話

24

AspectJ の主要概念• アスペクト • アドバイス• ポイントカット• 型間定義

aspect DisplayUpdating { pointcut move() : call(int FigElm.moveby(int,int)) || call(void Point.setX(int)) || call(void Point.setY(int)) || call(void Line.setP1(Point)) || call(void Line.setP2(Point)); after() : move() { Display.redraw(); }

void FigElm.draw(Display d); void Point.draw(Display d) { … } … }

aspect DisplayUpdating { pointcut move() : call(int FigElm.moveby(int,int)) || call(void Point.setX(int)) || call(void Point.setY(int)) || call(void Line.setP1(Point)) || call(void Line.setP2(Point)); after() : move() { Display.redraw(); }

void FigElm.draw(Display d); void Point.draw(Display d) { … } … }

move したら,その後でDisplay.redraw() を呼べmove したら,その後でDisplay.redraw() を呼べ

• 前後に追加する動作•置き換える動作cf. CLOS の before /

after / around メソッド

• 前後に追加する動作•置き換える動作cf. CLOS の before /

after / around メソッド

Page 23: アスペクト指向プログラミング に 関する十の神話

25

AspectJ の主要概念• アスペクト • アドバイス• ポイントカット• 型間定義

aspect DisplayUpdating { pointcut move() : call(int FigElm.moveby(int,int)) || call(void Point.setX(int)) || call(void Point.setY(int)) || call(void Line.setP1(Point)) || call(void Line.setP2(Point)); after() : move() { Display.redraw(); }

void FigElm.draw(Display d); void Point.draw(Display d) { … } … }

aspect DisplayUpdating { pointcut move() : call(int FigElm.moveby(int,int)) || call(void Point.setX(int)) || call(void Point.setY(int)) || call(void Line.setP1(Point)) || call(void Line.setP2(Point)); after() : move() { Display.redraw(); }

void FigElm.draw(Display d); void Point.draw(Display d) { … } … }

move するとは FigElm.moveby, Point.set

X, … を呼び出すこと

move するとは FigElm.moveby, Point.set

X, … を呼び出すこと

• メソッド呼出・フィールドアクセス・コンストラクタ実行・例外発生・ etc.

•組み合わせ・名前付け

• メソッド呼出・フィールドアクセス・コンストラクタ実行・例外発生・ etc.

•組み合わせ・名前付け

Page 24: アスペクト指向プログラミング に 関する十の神話

26

AspectJ の主要概念• アスペクト • アドバイス• ポイントカット• 型間定義

aspect DisplayUpdating { pointcut move() : call(int FigElm.moveby(int,int)) || call(void Point.setX(int)) || call(void Point.setY(int)) || call(void Line.setP1(Point)) || call(void Line.setP2(Point)); after() : move() { Display.redraw(); }

void FigElm.draw(Display d); void Point.draw(Display d) { … } … }

aspect DisplayUpdating { pointcut move() : call(int FigElm.moveby(int,int)) || call(void Point.setX(int)) || call(void Point.setY(int)) || call(void Line.setP1(Point)) || call(void Line.setP2(Point)); after() : move() { Display.redraw(); }

void FigElm.draw(Display d); void Point.draw(Display d) { … } … }

FigElm クラスに draw メソッドを追加

FigElm クラスに draw メソッドを追加

• メソッド・フィールドの追加

•親クラス・実装クラスの追加

• メソッド・フィールドの追加

•親クラス・実装クラスの追加

Page 25: アスペクト指向プログラミング に 関する十の神話

27

class Main {… }class Main {… }

AspectJ の実行モデル

class Point { int x, y; int getX() void moveby(int,int) void setX(int) }

class Point { int x, y; int getX() void moveby(int,int) void setX(int) }

class Line {… }class Line {… }

class FigElm { … }class FigElm { … }

aspect DisplayUpdating { pointcut move() : call(int FigElm.moveby(int,int)) || …; after() : move() { … } void FigElm.draw(Display d); void Point.draw(Display d) { … } … }

aspect DisplayUpdating { pointcut move() : call(int FigElm.moveby(int,int)) || …; after() : move() { … } void FigElm.draw(Display d); void Point.draw(Display d) { … } … }

class Display { … }class Display { … }

Pointx=1y=3

Pointx=1y=3

p.setX(10);p.setX(10);

setX(10) を呼び出す

10

Java======

Page 26: アスペクト指向プログラミング に 関する十の神話

28

class Main {… }class Main {… }

AspectJ の実行モデル

class Point { int x, y; int getX() void moveby(int,int) void setX(int) }

class Point { int x, y; int getX() void moveby(int,int) void setX(int) }

class Line {… }class Line {… }

class FigElm { … }class FigElm { … }

aspect DisplayUpdating { pointcut move() : call(int FigElm.moveby(int,int)) || …; after() : move() { … } void FigElm.draw(Display d); void Point.draw(Display d) { … } … }

aspect DisplayUpdating { pointcut move() : call(int FigElm.moveby(int,int)) || …; after() : move() { … } void FigElm.draw(Display d); void Point.draw(Display d) { … } … }

class Display { … }class Display { … }

Pointx=1y=3

Pointx=1y=3

p.setX(10);p.setX(10);

setX(10) を呼び出す

ポイントカットに合致

アドバイス本体を実行

画面を更新

draw を呼び出す

追加されたメソッドを実行

fig.draw(d);fig.draw(d);

結合点と呼ぶ

10

Page 27: アスペクト指向プログラミング に 関する十の神話

29

AspectJ の実行モデル• ポイントカット + アドバイス機構

– メソッド呼び出し等の各動作 (=結合点 ) が–ポイントカットに合致した場合に– アドバイスを前,後,あるいは置き換えて実行

• 型間宣言機構–各クラス (=結合点 ) が– 型パターンに合致した場合に– メソッド等の宣言が追加されたものとして扱う

Page 28: アスペクト指向プログラミング に 関する十の神話

30

what’s good? ― ポイントカット !

• FigElm ・ Point ・ Line に対する動作→ まとめて指定

横断的関心事をモジュール化 !

aspect DisplayUpdating { pointcut move() : call(int FigElm.moveby(int,int)) || call(void Point.setX(int)) || call(void Point.setY(int)) || call(void Line.setP1(Point)) || call(void Line.setP2(Point)); after() : move() { Display.redraw(); } … }

aspect DisplayUpdating { pointcut move() : call(int FigElm.moveby(int,int)) || call(void Point.setX(int)) || call(void Point.setY(int)) || call(void Line.setP1(Point)) || call(void Line.setP2(Point)); after() : move() { Display.redraw(); } … }

Page 29: アスペクト指向プログラミング に 関する十の神話

31

what’s good? ― ポイントカット !

• ワイルドカードによって簡潔に定義できる

• 例 : FigElm とその子クラスにある“ set” で始まる名前のメソッドが呼び出されたとき

aspect DisplayUpdating { pointcut move() : call(int FigElm.moveby(int,int)) ||

call(* FigElm+.set*(..)); after() : move() { Display.redraw(); } … }

aspect DisplayUpdating { pointcut move() : call(int FigElm.moveby(int,int)) ||

call(* FigElm+.set*(..)); after() : move() { Display.redraw(); } … }

Page 30: アスペクト指向プログラミング に 関する十の神話

32

what’s good? ― ポイントカット !

• 複雑な条件も指定できる

Q: p.moveby(2,3); は何回 redraw を呼ぶ ?

A: 3 回

class Point … {

void moveby(int dx, int dy) { setX(getX()+dx); setY(getY()+dy); } }

class Point … {

void moveby(int dx, int dy) { setX(getX()+dx); setY(getY()+dy); } }

aspect DisplayUpdating { pointcut move() : call(int FigElm.moveby(int,int)) ||

call(* FigElm+.set*(..)); after() : move() { Display.redraw(); } … }

aspect DisplayUpdating { pointcut move() : call(int FigElm.moveby(int,int)) ||

call(* FigElm+.set*(..)); after() : move() { Display.redraw(); } … }

1 回にするには ?

Page 31: アスペクト指向プログラミング に 関する十の神話

33

aspect DisplayUpdating { pointcut move() : call(int FigElm.moveby(int,int)) || call(* FigElm+.set*(..));

after() : move() && !cflowbelow(move()) { … } … }

aspect DisplayUpdating { pointcut move() : call(int FigElm.moveby(int,int)) || call(* FigElm+.set*(..));

after() : move() && !cflowbelow(move()) { … } … }

what’s good? ― ポイントカット !

• 複雑な条件の例 :

「 move() の中から 呼ばれたものを除く

move() 」

class Point … {

void moveby(int dx, int dy) { setX(getX()+dx); setY(getY()+dy); } }

class Point … {

void moveby(int dx, int dy) { setX(getX()+dx); setY(getY()+dy); } }

mainmain

setXsetX

movebymoveby

setYsetY

Page 32: アスペクト指向プログラミング に 関する十の神話

34

AspectJ 入門 : まとめ• アスペクト : 横断的関心事のためのモジュール• ポイントカット + アドバイス :

複数のモジュールで起きる動作に対し動作を追加する機構

• 型間定義複数のモジュールに対し,宣言を追加する機構

対象を指定する方法が強力(e.g.,ポイントカット )

Page 33: アスペクト指向プログラミング に 関する十の神話

35

AOP にまつわる神話• AOP の生い立ち

サブジェクト指向プログラミング

サブジェクト指向プログラミング

適応的プログラミング

適応的プログラミング

自己反映プログラミング自己反映

プログラミング

特定領域向け AOP( 分散・並列・・・ )特定領域向け AOP

( 分散・並列・・・ )

汎用 AOP汎用 AOP

開放型実現開放型実現

Page 34: アスペクト指向プログラミング に 関する十の神話

36

神話一 : AOP はオブジェクト指向の次に来るパラダイムだ

• プログラム言語は構造化プログラミング→抽象データ型→オブジェクト指向→アスペクト指向と進化している

• AOP オブジェクト指向の置き換え– むしろ追加的な機構

Page 35: アスペクト指向プログラミング に 関する十の神話

37

神話二 : AOP は OOP の欠点を改善する技術だ

• クラス・メソッドを使っても上手くモジュール化できなかったものをモジュール化するための技術

• OOP に限らずモジュールのある言語に有効

– AspectC [Coady 他 02]– AspectML [Dantas, Walker03]– レシピ !?

Page 36: アスペクト指向プログラミング に 関する十の神話

38

神話三 : アスペクトととは従属的なモジュールだ• 支配的なモジュール : 例 ) 図形の種類

→ クラスでモジュール化• 従属的モジュール : 例 ) 画面更新

→ アスペクトでモジュール化• 対等なモジュール分割どうしを合成す

るという考え方もある Hype/J [Ossher,Tarr01], CME

+ =

Page 37: アスペクト指向プログラミング に 関する十の神話

39

Hyper/J [Ossher01]

FigElmFigElm

PointgetX()getY()

setX(int)setY(int)

moveBy(int,int)

PointgetX()getY()

setX(int)setY(int)

moveBy(int,int)

LinegetP1()getP2()

setP1(Point)setP2(Point)

moveBy(int,int)

LinegetP1()getP2()

setP1(Point)setP2(Point)

moveBy(int,int)

FigureFigure

Displayupdate(FigElm)

Displayupdate(FigElm)

elementselements

displaydisplay

Observablemoved() {display.update(this);}

Observablemoved() {display.update(this);}

Displayupdate(FigElm)

Displayupdate(FigElm)

match Point.setX with Observable.moved

match Point.setY with Observable.moved

match Line.setP1 with Observable.moved

match Line.setP2 with Observable.moved

match Point.setX with Observable.moved

match Point.setY with Observable.moved

match Line.setP1 with Observable.moved

match Line.setP2 with Observable.moved

• 関心事ごとにクラス階層を作成(支配的なモジュールがない )

• 階層どうしを合成して実行– 合成方法を指定する言語

• 既存プログラムから関心事を抽出

Page 38: アスペクト指向プログラミング に 関する十の神話

40

神話四 : AOP は名前ベースの技術だ

• ポイントカットはメソッドの名前を使って時点を指定→名前を正しく

付けないとダメ• 現状はその通り• 「意味」に基くポイントカットが研究中

– 呼出し文脈 : cflow ・実行履歴 [Walker] ・将来の呼出し可能性 : predicted cflow [Kiczales03] ・データフロー [河内・増原 03] ・条件分岐 , ループ

aspect DisplayUpdating { pointcut move() : call(int FigElm.moveby(int,int)) ||

call(* FigElm+.set*(..)); after() : move() { Display.redraw(); } … }

aspect DisplayUpdating { pointcut move() : call(int FigElm.moveby(int,int)) ||

call(* FigElm+.set*(..)); after() : move() { Display.redraw(); } … }

Page 39: アスペクト指向プログラミング に 関する十の神話

41

神話五 : AOP はプログラム変換だ

• アスペクトとは、元のプログラムに埋め込まれて実行されるコードである → つまり AOP はプログラム変換の一種

• コードの埋め込み以上のことができる– 例 : 「 setX が実行時に moveBy を経ずに

実行されたときには再描画」

• コード変換に依らない処理系もある– steamloom: 仮想機械による織り込み [Bockisch 他 04]

– Wool:VM フックによる織り込み [ 佐藤・千葉・立堀 03]

Page 40: アスペクト指向プログラミング に 関する十の神話

42

神話六 : AOP は遅い• メソッド起動のたびにいちいちアドバイスを

探すのでオーバーヘッドが大きい• 実際はそうでもない

– コンパイル時にアドバイスを埋め込む [Hilsdale,Hugnin04][ 増原・ Kiczales ・ Dutchyn03]

– 静的解析による / 実行時の最適化 [Sereni,de Moor03][Hanenberg, Hirschfeld, Unland04]

– オーバーヘッドの計測 [Dufour et al.04]

Page 41: アスペクト指向プログラミング に 関する十の神話

43

神話七 : AOP はログをとるための技術

だ• それ以外の応用ってあるの ?

• ログ以外にも最適化・エラー処理などへの実際的な応用がある– FreeBSD カーネルを AOP で分離 [Coady 他 02,03]

アスペクト : プリフェッチ・クォータ・スケジューリング

– WebSphere のコードを AOP で分離 [Coyler04]アスペクト : ログ・エラー処理・監視

Page 42: アスペクト指向プログラミング に 関する十の神話

44

see: Y. Coady, G. Kiczales M. Feeley and G. Smolyn, Using AspectC to improve the modularity of path-specific customization in operating system code, in Proceedings of E

SEC-8 / FSE-9, pp.88-98, 2001,Vienna, Austria.

Page 43: アスペクト指向プログラミング に 関する十の神話

45

神話八 : AOP なんかいらない、デザインパターンで充分

• 「画面の再描画」は Subject-Observer パターンで実現可能

• 「実現」はできるが、–記述は散在してしまう– パターンを再利用できない

(AOP なら可能になる場合も [Hannemann

他 02])

Page 44: アスペクト指向プログラミング に 関する十の神話

46

神話九 : AOP はプログラミングを

難しくする• AOP で例えば「画面更新」を分離

→ Point, Line の定義から「画面更新」が無くなる→「画面更新」の影響範囲が特定できない→誤りを見つけるのが難しくなる

• 開発ツールによる支援– AJDT [Kiczales 他 01,…]

• OOP でも同じ議論が可能 ?→継承によって一部の定義を子クラスに→親クラスの定義の影響範囲が特定できない

Page 45: アスペクト指向プログラミング に 関する十の神話

47

see: Kersten, Clement, and Harley,

AspectJ Tools - New and Noteworthy, AOSD 2004 Demo.

Page 46: アスペクト指向プログラミング に 関する十の神話

48

神話十 : アスペクトはリファクタリングで抽出する

もの※ リファクタリング = プログラムの機能を変えず

に構造を改良する技術

• 横断的関心事は,プログラムを作ってみないと「横断的」かは分からないだろう

• そういう例は多い• 研究レベルでは,アスペクトの利用を前提とした開発方法論が提案– “Early Aspects” / “Aspect-Oriented Modeling” / Us

e-case Pointcuts [Sillito,Dutchyn,Eisenberg,De Volder04]

Page 47: アスペクト指向プログラミング に 関する十の神話

49

まとめにかえて : AOP の現状と将来

現状•沢山の懐疑論者

– 「便利そうだけど,大きなプログラムは書けない ? 」

– 「同じことは ××機構で頑張ればできるよ ? 」

– 「 ×× には使えないよ ? 」

将来

1980 年代の OOP• 沢山の言語・技術が提案(Smalltalk, C++, Flavors, バイトコード , JIT コンパイル , GC, IDE…)

• 理論よりも実践が先行• それから「当たり前」

になるのに 10 年当たり前 or 「そういえば昔, AOP なんてのがあっ

たなあ」

Page 48: アスペクト指向プログラミング に 関する十の神話

50

プログラミング言語の歴史FortranLisp

Smalltalk, C

C++

Java, GoF “Design Patterns”

C#AspectJ 0.3

1960

1970

1980

1990

2000

1955

1965

1975

1985

1995

最初のオブジェクト指向言語

実用的なオブジェクト指向言語

現存する最古の言語達Algol-60, COBOL

goto 有害説

オブジェクト指向があたり前の時代最初の汎用 AOP 言語

PL/1

SchemeProlog

Ada SML

Perl

RubyPython SOP

Simula-67Simula-67

Smalltalk-80Smalltalk-80

AspectJ 1.0実用的 AOP 言語

モジュール化

階層性・再利

Haskell

Page 49: アスペクト指向プログラミング に 関する十の神話

51

情報源など• 会議・論文誌

– Aspect-Oriented Software Development (AOSD)OOPSLA, ECOOP, ICSE, FSE, ICFP, …

– Trans. AOSD (Springer)

• ポータルサイト : aosd.net• メール :

[email protected][email protected][email protected]

• Kiczales’ talk @ ソフトウェア科学会大会 (2004年 9月 15日 , 東工大 )

Page 50: アスペクト指向プログラミング に 関する十の神話

52

おまけ