オブジェクト指向言語 Ld-2
Common Lisp 版

ユーザーズマニュアル
TR-98-19

一杉 裕志
電子技術総合研究所

1998 年 8 月 19 日

目次

1

はじめに

3

2

稼働システムとインストール方法

4

2.1
2.2
2.3
2.4

4
4
4
4

3

必要なソフトウエア

コンパイル : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :ロード: : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :サンプルプログラムの実行: : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :言語 Ld-2 の概要

5

3.1
3.2
3.3
3.4
3.5
3.6

5
5
5
6
6
6
6

Ld-2 の特徴 : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :ソフトウエアの部品： system mixin : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :system mixin の定義: defsystem : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :system mixin の結合 : setup : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :プログラムの起動 : start : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :メソッド探索順序

3.6.1
4: : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :: : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :クラスとモジュール : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :

言語仕様

8

4.1 system mixin の定義 : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :4.2 大域変数宣言 : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :4.3 クラス定義 : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :4.3.1 defclass : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :4.3.2 class : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :4.3.3 インスタンス変数宣言 : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :4.4 メソッド定義 : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :4.4.1 構文 : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :4.4.2 メソッド名について : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :4.4.3 abstract method : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :4.4.4 メソッドの役割 : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :4.5 メソッド呼び出し : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :4.6 オリジナルのメソッド呼び出し : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :4.7 インスタンス生成 : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :4.8 インスタンス変数へのアクセス : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :4.9 変数 *self* : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :4.10 Common Lisp 関数 : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :4.11 大域変数 : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :4.12 setup : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :4.13 start : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :

8
8
8
8
8
9
9
9
9
9
9
10
10
10
10
10
10
10
11
11

1

5

6

7

プログラム例

125.1 最小のプログラム例 : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :12

実行開発環境13

6.1 Emacs support : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :6.1.1 かぎかっことまるかっこの混在 : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :6.1.2 インデント : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :6.1.3 その他 : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :6.2 コンパイルとロード : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :6.3 デバッグ : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :6.3.1 info 文 : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :6.3.2 メソッド名 : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :6.3.3 Common Lisp のデバッグ機能 : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :6.3.4 インスタンス生成関数 : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :

13
13
13
13
13
13
13
13
13
14

クラスと部品の設計

15

7.1
7.2
7.3
7.4
7.5
7.6
7.7
7.8
8

9

設計・開発の流れ: : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :何をクラスにするか？ : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :継承関係はどう設計すべきか？

: : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :何を部品 (system mixin) にするか？ : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :
部品間の接続インターフェースは？ : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :
部品間の依存関係をシンプルにするには？

: : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :

部品間の競合関係を少なくするには？ : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :追加部品はどう実装すべきか？

: : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :

15
15
15
16
16
16
17
17

実装ノート

18

8.1 実装の概要 : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :8.2 トランスレーター : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :8.3 実行時システム : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :8.3.1 クラス : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :8.3.2 オブジェクト : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :8.3.3 メソッド呼び出し : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :8.3.4 インスタンス変数 : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :8.3.5 大域変数 : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :

18
18
18
18
18
18
18
18

将来の機能拡張202

第 1 章はじめに
本マニュアルでは Common Lisp 上で動くオブジェク

室、企業レベルでも実用的なものが提供可能になる。

ト指向パッケージ Ld-2 の言語仕様と使い方について述べ

Ld-2 は現在のところ単一継承で、静的型や情報隠蔽のる。マニュアルを読むには、 Common Lisp のシンタッ機能を持たないシンプルなオブジェクト指向言語である。

クスとオブジェクト指向に関する基礎的な知識が必要であ

一方、 system mixin と呼ぶソフトウエアの部品化をサる。

ポートする特徴的な機構を持っている。メソッドの内部記
述言語や実行・開発環境は Common Lisp のものを使う。

本文中では、 gcl-2.1 (Gnu Common Lisp) を使った実同じだが、特にデバッグ関係は処理系ごとに異なるので注

Ld-2 は Common Lisp のマクロを使って実現されており、 Common Lisp (ただし CLOS は不要) が稼働する環意してほしい。

境ならばどこでも利用可能である。

行例を載せている。他の Common Lisp 処理系でもほぼプログラミング言語 Ld-2 は、ソフトウエアの部品化を

Ld-2 は、オブジェクト指向の継承が持つ機能のうち、サポートするシンプルなオブジェクト指向言語である。こ

部品化の機能にのみ重点を置いて設計されている。また、こで言う部品化とは、ソフトウエア開発者だけでなくソフプログラマーの便宜よりも部品の組み合わせを行なうアプ

トウエア利用者にとっても利益のある部品化である。 Ld-

リケーションユーザの便宜を優先した機能をいくつか持っ2 で書かれたアプリケーションの利用者は、ソフトウエアている。プログラマーに特定のプログラミングスタイルを

部品を選択して組み合わせることによって、ソフトウエア

強制しプログラミングの自由度を奪うような機能は一切入を様々なコンフィギュレーションにカスタマイズすることれていない。

ができる。また、既存の部品を変更拡張して新しい機能を追加することも容易である。従来は、エンドユーザによるソフトウエアのコンフィギュレーションは、 #ifdef, patch,
プラグインなどの形で行なわれてきたが、これらの方法よ
なお、このドキュメントは最初、 1997 年 2 月に書かれりも自然な記述で、はるかに多様性の高いアプリケーショ

たものだが、少し手直しして、 1998 年 8 月にテクニカルンを提供することができる。

Ld-2 は、コンパイラキット Lods の記述言語として設レポートにしたものである。

Ld-2 は、最初コンパイラキット Lods の記述言語とし計・開発された。コンパイラキット Lods は、プログラミて開発されたが、 1997 年 3 月には、拡張可能 Java プリ

ング言語の進化速度促進を目指し、言語処理系を機能単位

プロセッサ EPP Common Lisp 版の記述に使われた。まで部品化し、部品間の接続インターフェースを標準化する

た、 Ld-2 とほぼ同じ機能を Java 言語に追加する \Sys-

ことによって、非常に幅広い範囲の言語処理系を容易に構

temMixin plug-in" が、 EPP の上で実装されている [18]。

築できるようにすることを目指している。

Lods は、単なる言語処理系作成者のためのクラスライ
ブラリにとどまらず、言語ユーザにとっても利益あるものを目指している。言語ユーザは言語実装部品の中身の詳細をしらなくても、部品を追加・交換するだけで、新しい言語機能や新しい実装方式を利用することができる。
ちょうど PC 互換機を組み立てるユーザのように、実装の詳細に関する知識は必要とせず、何と何が接続可能かという知識さえあればよい。
このような言語処理系と接続インターフェースが提供されていれば、個々の言語処理系部品は比較的小規模な研究3

第 2 章稼働システムとインストール方法
2.1

必要なソフトウエア

いわゆる CLtL の第１版に準じた Common Lisp 処理系が必要である。 CLOS (Common Lisp Object Sys-tem) は必要ない。また、ＯＳには全く依存しない。現在のところ、以下の処理系で動作が確認されている。

 gcl on SunOS, Solaris ecl on SunOS clisp on SunOS, Windows95

2.2

コンパイル

まず Common Lisp 処理系をインストールする。次に、ファイル ld-2.lsp があるディレクトリに移動し、 Com-

mon Lisp を起動して、(compile-file "ld-2.lsp")を実行する。

2.3

ロード

Ld-2 を使えるようにするには、ソースファイル ld-2.lsp
をコンパイルしてできたファイル ld-2.o があるディレク
トリに移動し、 Common Lisp を起動して、(load "ld-2.o") あるいは (require 'ld-2)を実行する。ファイルのサフィックスは、 OS や Com-

mon Lisp 処理系によって違うので注意すること。

2.4

サンプルプログラムの実行

サンプルプログラムが置いてあるディレクトリ（まだ作ってない）に移動し、(load "file-name.lsp")を実行する。

4

第 3 章
言語 Ld-2 の概要
3.1

Ld-2 の特徴(defsystem <<S>> ()(defclass <super> ()Ld-2 は、以下の特徴を有する。
(no-orig); super class なし
 system mixin と呼ぶ部品化を支援する機構を有する。
(variable !v); インスタンス変数の定義
 Common Lisp 上でマクロを使って実装されたシン(defmethod :init () ; 初期化メソッド
プルなオブジェクト指向言語。メソッド内の動作記述(setf !v 0))には Common Lisp そのものを使う。
(defmethod :add (x) ; メソッドの定義(setf !v (+ !v x)))) エンドユーザによる「部品」の組み合わせ時のエラー(defclass<sub> ()
チェックの機構を有する。
(orig <super>); super class の指定
 今のところ、単一継承であり静的型チェックと情報隠(method :add (x); メソッドの拡張
蔽の機能はない。
(print x)
 Smalltalk のクラス変数、クラスメソッドのようなも[:original x]) ; super のメソッドの呼び出し
のはない。
)
)
3.2 ソフトウエアの部品： system mixin
図 3.2: システムとクラスの定義

Ld-2 では、一つのソフトウエアを部品に分割したもの
を system mixin と呼ぶ。この system mixin を複数組み合わせることにより、一つの完全なアプリケーションとしである。 system mixin は従来の言語の「モジュール」にて実行可能な状態にする。

近い役割も持つ。

system mixin は他のシステムに対する変更・拡張の差
system mixin は、 unix の patch ファイルのようなも分部分を定義したものである。具体的には、クラスの追加、 のだが、変更・拡張の単位は行単位ではなくクラスやメソッ
既存のクラスへのインスタンス変数・メソッドの追加、既ド単位である。 patch ファイルでは変更箇所の指定は前存のメソッドの再定義・拡張を記述したものが system mixin 後の文脈を用いるため、複数の patch の同時適用が意図した通りに行なわれない可能性がある。 system mixin では、変更箇所はクラス名・メソッド名を用いて指定されるため、そのような問題はない。
複数の system mixin を記述し、それを１列に並べて組み合わせることにより一つのシステムが構築される（図 3.1）。

個々の system mixin は、クラス階層の一部分を記述したもので、それらを重ねることによって、クラス階層の全体が完成する。

3.3

system mixin の定義: defsystemsystem mixin の定義は図 3.2のように行なう。この例

図 3.1: system mixin の結合では、クラス <super> と、そのサブクラス <sub> を持5

通常の継承ではメソッドやインスタンス変数を追加した subclass を定義しても他の兄弟の subclass には全く影響はな
いが、 system mixin を使った super class への変更は、全ての subclass にそのまま継承される。

(setq x [:<sub>]); クラス <sub> のインスタンス生成[x :add 1]; x のメソッド呼び出し[:my-method 123] ; 自分自身のメソッド呼び出し
図 3.3: インスタンス生成とメソッド呼び出し

3.4

system mixin の結合 : setup

system mixin を一列につなぎあわせることにより、一

つ system mixin <<S>> を定義している。

(orig <class-name>) は super class の指定、 (no-orig)
は、 super class を持たないことを示す。

つのシステムが完成する。これには、トップレベルで以下の式を実行する。

(setup (list <<Sn>> ... <<S2>> <<S1>>))

インスタンス変数には名前の先頭に \!" をつける。

defmethod は新しいメソッドを定義する時に使い、
method はすでにあるメソッドを拡張する時に使う構文である。 method 構文の内部では、 [:original arg ...]

リストのもっとも右にある system mixin がオリジナルのシステムであり、それに次々に変更を加えていったものが結果のシステムとなる。

という式によって、 super class の同じ名前のメソッドを呼び出せる。

3.5

図 3.3は、インスタンス生成とメソッド呼び出しの例でプログラムの起動 : start

プログラムの起動は、 (start) という関数で行なう。

ある。かぎかっこの第一引数はメソッドを送るオブジェク

ト、第二引数はメソッド名、残りはメソッドの引数である。 これにより直前に setup によって定義されたシステムの<startup> というクラスが生成され、その初期化メソッ

かぎかっこの第一引数にメソッド名が来た時には、そのイ

ド :init が実行される。プログラムの実行は、このメソッンスタンス自身のメソッド呼び出しを意味する。クラス名

ド :init から開始される。

をメソッド名として用いた場合は、そのクラスのインスタ

system mixin の結合時に、クラスやメソッドの二重定

ンスを生成するメソッドと解釈される。
図 3.2 のクラス <super> にインスタンス変数 v2 とそ義、未定義のエラーがチェックされる。例えば全てのクラの初期化のコードを追加する system mixin は、以下のよスに対し、構文 (defclass ...) による定義がちょうどうに定義する。

一つだけないとエラーとなる。クラス内の各メソッドに対しても同様である。

(defsystem <<add-v2>> ()(class <super> ()(variable !v2)
(method :init ()[:original](setf !v2 0))))3.6

メソッド探索順序

system mixin の中の defclass または class で定義される「クラス定義の断片」を class mixin と呼ぶ1 。つまり、 system mixin は複数の class mixin から構成される。同様に class mixin の中にある「メソッド定義の断片」は method mixin と呼ぶ。 system mixin を結合した段階で、各クラスの class mixin も一列に結合される。
class mixin は、 system mixin 結合順序およびクラス間の継承関係によって、図 3.4のように直列化される。これを class mixin list と呼ぶ。メソッドの探索は、この classmixin list の先頭から行なわれる。すなわち、「 subclass(class ...) という構文は、すでに定義されているクラスを拡張する時に defclass の代わりに使う。
<<S>> に <<add-v2>> を追加した結果できるシステム
では、クラス <super> はあたかも以下のように定義されたかのように振舞う。

(defclass <super> ()(no-orig)(variable !v)(variable !v2)
(defmethod :init ()(setf !v 0)(setf !v2 0))(defmethod :add (x)(setf !v (+ !v x))))

優先」という従来のルールに加えて、「後から追加された

system mixin 優先」（この図での左側）というルールに
従う。

3.6.1

クラスとモジュール

再利用性・拡張性の高いアプリケーションの記述にはオブジェクト指向言語が有効である。しかし、多くのオブジェ
1 これは

6

avors や CLOS でいう mixin に相当する。

<A>

<A>

<A>

<B>

<B>

<B>

<C>

<C>

<C>

System mixins
図 3.4: class mixin list
クト指向言語ではクラスの機構がモジュールの機構を兼ねており、その問題点が指摘されている [17]。本来クラスは動的に生成されるデータ構造の雛型あるいはポリモーフィ
ズムの単位であり、モジュールは機能ごとの内部実装の隠蔽や再利用の単位である。アプリケーションによってはこの２つの概念がほぼ一致することもあるが、一般には全く異なる。例えば、複数のクラスが互いの内部実装に依存しながら１つの機能を実現したり、１つのクラスが複数の機能に密接に関わっている場合がある。特にコンパイラ記述
においては、クラス間の依存関係は複雑であり、従来のオブジェクト指向言語が持つ継承機構だけでは部品化が困難である。

Ld-2 では、ある機能を実現するコードを１つの system
mixin にまとめて記述することによって、モジュールを実現することができる。（ただし、情報隠蔽の機構はまだ実装されていない。）従来のオブジェクト指向言語と違い、複数のクラスを一つのモジュールにしたり、一つのクラスのメソッドを複数のモジュールに分割して記述することができる。
より詳しい議論は、 7章を参照のこと。

7

第 4 章
言語仕様
4.1

system mixin の定義

global-variable ::=(global-variable !!gvar-name)defsystem ::=(defsystem <<system-name>>(defsystem-option-list)
defsystem-toplevel-list)

なお Common Lisp の defvar 宣言による大域変数（特殊変数）も使えるが、この構文の使用を推奨する。
大域変数値の初期化はされない。クラス <startup> の:init メソッドなどで、明示的に初期化を行なう必要があ

defsystem-option-list ::=| defsystem-option defsystem-option-list

る。

defsystem-option ::=decl-dependency | ...

4.3

クラス定義

4.3.1

defclass

defclass は新しいクラスを定義するための構文である。

defsystem-toplevel-list ::=| defsystem-toplevel defsystem-toplevel-listdefclass ::=(defclass <class-name> (defclass-option-list)
decl-orig
defsystem-toplevel ::=defclass-toplevel-list)
global-variable | defclass | classdefclass-option-list ::= Not defined yet.

decl-dependency ::=(depend dependency-list)

decl-orig ::= (no-orig) | (orig <class-name>)

dependency-list の部分には、この system mixin が依存する system mixin の名前を書くことができる。 setup
時に、ある system mixin に依存する部品が list の前に来defclass-toplevel-list ::=| defclass-toplevel defclass-toplevel-listていないと、エラーとなる。（この機能は未実装。）ここで「A が B に依存する」とは、 A および A が依存する

defclass-toplevel ::=variable | defmethod | method

system mixin 中で定義された資源名（大域変数名、クラス名、メソッド名、インスタンス変数名）を B の中で参

defclass 構文は、必ず :init という名前のメソッド定義照していることを言う。

を含んでいなければならない。初期化の必要が特になくて

現在の実装では、依存の宣言と実際の依存関係との食い違いをチェックしていない。将来の実装では、宣言されたも、 (defmethod :init ()) と書いておく必要がある。

system mixin で定義されていない名前を参照していると
setup 時にエラーを出すようになるかもしれない。

4.3.2

4.2

class

class は既存のクラスを拡張するための構文である。

大域変数宣言class ::=
(class <class-name> (class-option-list)
defclass-toplevel-list)

Ld-2 の大域変数宣言は、 defsystem の中に次のように書く。

8エラーとなるが、 Ld-2 ではそのようなチェックはやっていない。その代わりに、実行時に abstract method を呼class-option-list ::= Not defined yet.

class 構文によって、既存のクラスに対してインスタン

び出した時に実行時エラーとなる。

ス変数の追加、メソッドの追加、既存のメソッドの再定義

abstract system mixin と呼ぶ。

なお、 abstract method だけを含む system mixin ををすることができる。

4.3.3

4.4.4

インスタンス変数宣言

この節で述べる機能は、現在完全には実装されていない。

defclass および class 構文の中で、インスタンス変数の

前節の abstract method をさらに拡張した機能である。

宣言を行なうことができる。

すべてのメソッド定義は、 defmethod/method の違い

variable ::=(variable !var-name)とは別に、「メソッドの役割」を持つ。メソッドの役割には、 abstract, default, implement, extend, rede ne の５種類がある。すべての method mixin は、これらのうち

値の初期化は、 :init メソッド内で行なう。

4.4
4.4.1

のいずれかの役割を持つ。メソッドの役割は、各メソッド
定義の body の最初で宣言する。

メソッド定義例：(defclass <a-data> ()(no-orig)(defmethod :size ();; The role of this method mixin is \default".
(default)
1)
...)

構文

defmethod は新しいメソッドを定義する構文、 method
は既存のメソッドを再定義する構文である。

defmethod ::=(defmethod :method-name lambda-list body)method ::=(method :method-name lambda-list body)

メソッドの役割は、継承によるメソッドの再定義に制限をつける。例えば、 implement method を他の imple-

ment method で再定義できない。 setup の際このように

lambda-list ::= Defined by Common Lisp.

制限に反するメソッド再定義が見つかった場合、エラーとなる。この制限によって、ある機能を実装する異なる部品

lambda-list には、 &optional, &rest など Common
Lisp の機能がすべて利用できる。
4.4.2

メソッドの役割が２つ指定されて衝突し、正しく動作しないことを未然に防ぐことができる。
それぞれのメソッドの役割の意味は以下の通りである。

メソッド名について

 abstract

defmethod で宣言する名前は、全 system mixin 中でいわゆる abstract method 、すなわちインターフェー

重複しないようにすべきである。（ただし属するクラスがスのみを定義し実装を定義しないメソッド宣言である。

異なれば重複してもよい。）また、名前とその役割の対応

defmethod 構文でのみ使える。実行時にこの method
mixin が呼び出されるとエラーである。

は、全 system mixin 中でコンセンサスがとれているものと仮定する。（巨大なアプリケーションを構築するために default

は名前空間を分ける機構が必要になってくるだろうが、いdefault method は、他の method mixin によって全

まのところそれはない。）

く別のものに再定義されることを許すメソッドである。

4.4.3

default method は abstract, default method を再定

abstract method

義できる。 default method は、 defmethod およびインターフェースだけを定義し、実装を定義しないいわ
ゆる abstract method は、次のように書く。

method 構文で使える。 defmethod 構文では、 (default) 宣言は省略可能である。従って、先の例は、以(defmethod :method-name (args ...) (abstract))

下のようにも書ける。

C++ や Java では abstract method を一つでも持つクラ例：

スに対してインスタンスを生成しようとするとコンパイル(defclass <a-data> ()9(no-orig)(defmethod :size ();; Implicitly declared as \default".
1)
...)

4.8

インスタンス変数へのアクセス

インスタンス変数の値の参照は !var 、代入は (setf !varval) で行なう。（setf を setq と間違いやすいので注意。）

実は、 !var は [:var] 、 (setf !var val) は [:set-var val] というメソッド呼び出し式として解釈される。メソッド :var,:set-var は、クラスに (variable !var) という宣言がdefault method は、 :original 呼び出しを含んでいあると自動的に定義される。インスタンス変数へのアクセてもいなくてもよい。

スがメソッド呼び出しを通して行なわれるため、以下のこ implementとが可能である。

abstract, default method を再定義できるメソッド。:orig 他のオブジェクトのインスタンス変数にもアクセスで
inal 呼び出しを含んでいてはいけない。 defmethod
きる。例えば [obj :x] というメソッド呼び出しはオブおよび method 構文で使える。
ジェクト obj の !x というインスタンス変数の値を取 extend
り出す。また、 [obj :set-x 0] は、 !x の値に 0 を代
default, implement, extend, rede ne method を再入する。
定義できるメソッド。:original 呼び出しを必ず含ま サブクラスでアクセスメソッドを再定義することがでなければならない。 method 構文では、 (extend) 宣
きる。
言は省略可能である。 method 構文でのみ使える。
例： rede ne(method :set-x (val)(print "Value of x is changed!")[:original val])

abstract, default, imlement, extend, rede ne method
を再定義できるメソッド。:original 呼び出しを含んでいてはいけない。このメソッドは、「間違った役割宣言をしたメソッド」を再定義したい時などに有効で4.9ある。 rede ne method の仕様は、部品組み合わせの危険度を増すので注意が必要である。 method 構

変数 *self*

メソッド中では、変数 *self* の値が自分自身を指している。つまり、式 [:foo] は [*self* :foo] とまっ

文でのみ使える。

たく同じ意味である。

4.5

メソッド呼び出し

4.10[obj :method-name args ...] は、 obj のメソッド:method-name を呼び出す。
[:method-name args ...] は、自分自身のメソッド:method-name を呼び出す。
4.6

高階関数を含む全ての Common Lisp 関数をメソッド中から呼び出すことができる。また、インスタンス変数へのアクセスやメソッド呼び出し式を含む関数を defun で定義することができる。
ただし、現在の実装では変数 *self* は dynamic scope

オリジナルのメソッド呼び出しに従うので注意すること。例えば、インスタンス変数へのアクセスを含む関数 closure を、他のオブジェクトのメ[:original args ...] という式は、いわゆる「 su-

ソッドの引数に渡すと、 *self* の値はその受け手のオブ

per class のメソッド呼び出し」に相当する。より厳密にジェクトになるので、送り手側のインスタンス変数にはア

言うと、 class mixin list （3.6参照）にしたがって次のクセスできない。このように混乱のもとになるので、関数

method mixin を探索し、呼び出す。
4.7

Common Lisp 関数

closure をメソッドの引数に渡すようなインターフェース

設計は推奨しない。関数 closure の代わりにオブジェクト

インスタンス生成を用いること。

[:<class-name> args ...] という式によってインスタンスが生成される。引数はそのまま、そのクラスの :init

4.11

大域変数

大域変数へのアクセスは !!gvar 、 (setf !!gvar val) といメソッドに渡される。
メソッド :<class-name> を再定義することはできる

う式によって行なう。また、動的スコープに従って値を変更するためのマクロとして let-g がある。

が、推奨しない。

10例：(let-g ((!!gvar1 val1)(!!gvar2 val2)...)
body ...)
4.12

setup

トップレベルで system を再定義した時は、原則として
setup し直さなければならない。
setup 時に、以下のチェックが行なわれる。この機能により、エンドユーザが「意味のある」部品の指定を行なったかどうかをある程度検出できる。

 すべてのクラス名に対して、 defclass の前に classが来ていないか。同じ名前の defclass が２重になってないか。

 すべてのクラス内のメソッドについて、 defmethodの後に method が来ていないか。 defmethod が２重になっていないか。

4.13

start

関数 start は、 setup によって構築されたシステムの起動を行なう。関数 start が呼ばれると、まず <startup>というクラスのインスタンスを生成し、その :init メソッドに関数 start の引数の値を渡す。:init メソッドの実行が終了すると、トップレベルに戻る。:init メソッドの返値は無視される。

11

第 5 章プログラム例
5.1

最小のプログラム例

Ld-2 の最小のプログラム例は次のようになる。
(defsystem <
> ()(defclass <startup> ()(no-orig)(defmethod :init ()(print "Hello World."))))(setup (list <
>))12

第 6 章
実行開発環境6.1
6.1.1に複数の system mixin を入れてもよい。 sys-a.lsp を load

Emacs support

するには、 (load \sys-a.lsp") を実行する。このファイル

をコンパイルするには、 (compile- le \sys-a.lsp") を実

かぎかっことまるかっこの混在

行する。

Emacs のデフォルトの lisp-emacs では、かぎかっこ
が かっこ として認識されない。これに対処するため、付属の paren.el を使用する。このパッケージには、かぎかっ
こ と まるかっこ の対応が会っていないと beep をならす、などの機能がある。

6.3

デバッグ

6.3.1

info 文(info object) または (info <class>) によって、

それでも、開きかっこの削除などによって編集中にかっ
この対応が狂うことはある。 gcl の場合 load 中にエラーオブジェクトやクラスの情報を得ることができる。

おきた場所の次の行が表示され、エラーの場所が特定でき

ス変数は表示されない。

がでたら (read-line) を何度か入力してみると、エラーがなお、このとき、値がまだ代入されていないインスタンる場合がある。

6.1.2

6.3.2

インデント

メソッド名

Ld-2 のメソッドは、 Common Lisp の処理系上では

Ld-2 の構文のいくつかは、デフォルトの lisp-mode ではうまくインデントできない。 Emacs Ver.18 の場合、
以下のように .emacs に入れる。 Emacs のその他のバー<<システム名>>/<クラス名>/ メソッド名という名前の関数として実行される。

ジョンでも動くかどうかは不明。

もし実行時エラーが起きて Common Lisp のデバッガーに入ったら、 backtrace すれば、どのメソッドでエラーが(load "cl-indent")
起きたのかを知ることができる。また、 Common Lisp
(put 'method 'common-lisp-indent-hookの trace 文の引数にこのメソッド名を使うこともできる。
'(4 (&whole 4 &rest 1) &body))(put 'class 'common-lisp-indent-hook'(4 (&whole 4 &rest 1) &body))
6.3.3 Common Lisp のデバッグ機能(setq lisp-indent-hook 'common-lisp-indent-hook)break, trace, step などのデバッグ機能は Common Lisp

6.1.3のものがそのまま使える。メソッド実行中の実行時エラー

その他

や break 文によってデバッガに入った場合、そのオブジェ

クト自身が特殊変数 *self* に束縛されている。従って、その他は Common Lisp の開発環境がそのまま利用でデバッガのプロンプトから、インスタンス変数・大域変数きる。

へのアクセス、メソッド呼び出しなどが行なえる。

6.2

コンパイルとロード
例：[other-obj :mess][:print]!a(info *self*)

Ld-2 のプログラムは、通常の Common Lisp のプログ
ラムと全く同じようにコンパイル・ロードすることができる。以下は、 gcl での例である。プログラムは、 .lsp をサ
フィックスに持つファイルに記述される。１つのファイル

136.3.4

インスタンス生成関数

break 等でデバッガに入った場合は、通常のプログラム
内と同様に [:<class-name>] によってインスタンスを生成できる。
しかし、 toplevel では上記のメソッド呼び出し式はエラーとなる1 。そのような場合は、代替手段として、インスタンス生成関数が利用できる。 (<class-name> args...) を実行すると、インスタンスが生成される。引数は、 :init メソッドの引数に渡される。ただし、このように関数 start を通さずにクラスを生成してメソッド呼び出しを行なうと、大域変数の設定が行なわれていないので、大域変数へのアクセスはエラーとなるので注意。

1 変数 *self* 等の値が設定されていないため。

14

第 7 章クラスと部品の設計
7.1

 ポリモーフィズムが必要な時。

設計・開発の流れ「あるクラスの実装に依存する手続きは、そのクラスの「極めて多様なコンフィギュレーションが可能なアプリ

メソッドにする」というルールは、 Ld-2 ではむしろ忘れ

ケーション」を Ld-2 で設計・開発する手順は、おおよそた方がよい。これはクラスの役割とモジュール (system mixin)

次のようになる。

1. 作りたいアプリケーションが決まったら、何をクラスにするかを設計する。アプリケーションのコンフィギュ
レーションが変わっても、各クラスの役割は変わらない点に注意する。

の役割を混同している。相互に密接に関連するソースコー
ドは同じ system mixin に入れた方がいいが、同じクラスにする必要はない。クラスは、必ずしもカプセル化の単位として適切ではない。

2. コンフィギュレーションを１つに固定して、アプリケー
7.3
ションを実装してみる。最初は system mixin の切り継承関係はどう設計すべきか？

 Ld-2 は system mixin の機能を持っているため、分け方は大雑把でよい。

3. 「交換できる機能」を１つずつ増やしていく。それにともなって、ソースコード全体を system mixin に分割していく。必要に応じて \hook" メソッド1 を入れコードの再利用、あるいは差分プログラミングというていく。接続インターフェースも汎用性の高いものにことなく、差分的に機能を追加することができる。必徐々に変えていく。

要もないのに差分的変更のためだけに subclass を作

4. 部品間の依存関係・競合関係を整理する。そのためには、 abstract system mixin （4.4.3節）の導入や、メソッド定義場所の移動などを行なう。

5. ある程度接続インターフェースが安定してくると、システムを公開する。公開された接続インターフェースに依存する実装部品がたくさん作られるようになる。
この段階になると、もはや接続インターフェースや部品の切り分け方の大規模な変更は許されなくなる。た7.2

目的だけなら、必ずしも subclass を作る必要はない。

system mixin を追加すれば、クラスの名前を変える

ると、クラス名が別のものになってしまう。そうすると、そのクラス名をソースコード中に埋め込んでいる
他の部品は使えなくなってしまう。つまり、部品の組
み合わせの自由度が著しく減ってしまう。

 一般に is-a 関係にあるクラスは subclass にした方がよいが、 Ld-2 では必ずしもそうでない場合もある。

例として Lods の <frame-manager> というクラスがある。 Lods では言語のスタックフレームの実装のバだし、メリットが大きければ局所的な接続インターフェー

リエーションとして、配列を使ったフレームと、 Cスの変更はその後も行なわれ続ける。

のスタックをそのまま使ったフレームの２種類を実装した。２つの <frame-manager> クラスを、１つの<abstract-frame-manager> クラスの subclass にす

何をクラスにするか？

る方法もあるが、実際のコンパイラで使用されるのは２つの場合がある。

通常どちらか一方だけである。そこで、 frame-manager

 構造体の代わり。つまり、複雑なデータ構造を一つののクラスはただ１つのみで、その複数の実装を異なる

ポインタで指したくなった時。あるいは同じ構造をしsystem mixin で記述して交換できるようにした。

たデータを動的に複数生成したい時。もちろん、それ Ld-2 には今のところ静的型システムはないので、クに対する操作はメソッドとして定義する。

ラスのインターフェースの階層構造は、継承関係に反1 再定義で拡張されることだけを目的としたメソッドをこう呼んでい映させる必要は全くない。「ソースコードの共有」という性質にのみ着目して継承関係や部品化の設計を行る。

15なうべきである。

 クラスがモジュールとは違うのと同様に、継承関係はモジュールのネスト構造を表現する手段ではないので対応しているわけではない。複数の部品が協力して１つの接続インターフェースを実装することもあるし、１つの部品が複数の接続インターフェースを実装することもある。
例えば Lods における heap-manager を実装する部品は、注意する。

「メモリの割り当てを行なうオブジェクトに関する接続イ

何を部品 (system mixin) にするか？

ンターフェース」と、「ＧＣを実装する部品の接続インター 「交換」が想定される部分を「部品化」する。部品化

数の異なった目的の利用者に対する複数の接続インターフェー

7.4

フェース」の両方を実装する。つまり、１つの部品が、複とは、ソースコードを複数の system mixin に分割しスを実装していることになる。（ java の「interface の多て記述することである。相互に密接に依存し合ってい重継承」を使う状況に近いかもしれない。）
接続インターフェースの設計には以下の点に注意する。

る、あるいは特定の実装に依存しているものは、できるだけ１つの system mixin にまとめた方がよい。

 接続インターフェースはできるだけ抽象度が高く汎用

 他の system mixin の実装に依存する system mixin

的で安定している方がよい。しかし、完全なインター

は絶対に存在してはいけない、というわけではない。

フェースを最初から設計するのは絶対に不可能である。

「部品の内部は隠蔽されていて、公開された固定した

従っていろいろな部品を実装しながら必要に応じて徐々インターフェースのみを通してアクセスしなければなに変更していく必要がある。

らない」というルールは保守性を高めるためには必要

 需要のない接続インターフェースの設計に時間をかけだが、それを犠牲にすることで部品の種類の多様化がてはいけない。部品が交換できれば便利そうだと思っ図れる場合がある。例えばある部品 A に追加する機た機能のインターフェースだけを注意して設計する。

能の実装方法に２種類あり、どちらにするかをエンド交換できても意味のない部分は無理して複数の部品にユーザが選択可能にしたいならば、追加機能を別の部分ける必要がない。

品 B1 、 B2 として実装せざるを得ない。このような場合、コンフィギュレーションの多様性と、保守のし接続インターフェースは本来、ソースコード上に実体のない抽象的な存在だが、 abstract system mixin の形で接やすさとのトレードオフを考えて設計する。

 デザインパターン [9] のうち、 decorator は Ld-2 で

続インターフェースの subset を記述することはできる。

は必要ない場合が多い。 Ld-2 の system mixin を使

これと他の機能（4.1節、 4.4.4節）を組み合わせることにえばもっと直接的に、拡張性の高いソフトウエアが書

よって、ある機能の実装側と利用側が接続インターフェー

ける。動的に機能を変更できるという点では、 deco-

スを正しく満たしているかどうかの必要条件を自動的にチェッ

rator パターンを用いた方が高機能である。しかし、クできる。（現在はこのチェック機能は実装されていない。）

Lods をもし普通のオブジェクト指向言語で動的に機

7.6

記述は高機能な分、複雑になる2 。コンパイラキット
能変更できるスタイルで書いたら、多数の種類の dec-

orator が入り組んで多分とても保守できない。

部品間の依存関係をシンプルにするには？

モジュール間の依存関係は一般には有向グラフになる。
依存関係は、部品の組み合わせの自由度を制限するので、7.5

できるだけ依存グラフはシンプルな方がよい。（例えば大部品間の接続インターフェースは？

規模なループなどは好ましくない。）また、ある部品に依接続インターフェースとは、ある機能を実装する側のコー 存する場合でも、できるだけ「強くは」依存しないようにドと利用する側のコードが、どの資源名（クラス名、メソッ した方がよい。それには、いくつかの方法がある。
ド名、インスタンス変数名など）をどのように用いて相互 相互に強く依存するメソッドをできるだけ一つの sys-

作用するかを定義したものである。モジュール機能を持つ

tem mixin の中に押し込める。

言語におけるモジュールインターフェースとは少し違うので注意。（モジュールインターフェースは、モジュールの 他の system mixin の変化が激しそうなメソッドに依

内部を隠蔽し、モジュールの利用者がどのようにしてその存している場所があったら、より安定したメソッドをモジュールを利用するかを定義したものである。）モジュー

通して間接依存する形に書き直す。

 複数の部品間で相互依存関係が生じる場合は、 abstract

ルの実装とモジュールインターフェースは１対１に対応すsystem mixin を導入し、相互依存関係を解消する。

る。部品接続インターフェースは、特定の部品と１対１に2 なお、部品の記述は現在のままで、動的に system mixin を交換で（図）。例えばＡとＢが相互依存している場合、Ａ、Ｂ内で定義されている資源名を abstract system mixin

きるような機能を Ld-2 の将来の追加機能として考えている。

16

 拡張性を高くしておくこと。（多くのメソッドを変更・Ｉの形で抜き出せば、Ａ、ＢがそれぞれＩに依存する
木構造に変えることができる。

 大域変数をうまく使えば、部品間の依存関係を簡単化

拡張を想定した形で記述すること。）
もちろんこれらの間にはトレードオフが必要なこともある。

できる。クラスを設計する段階で、何を大域変数にすべきかも同時に考える。一般にアプリケーション全体に関係した「状態」を表すオブジェクトは、多くのメ
ソッドの引数にしてひきずり回すよりも、大域変数にした方がよい。
理想的には、 abstract method だけを含む system mixinと実装だけを含む system mixin に完全に分けて記述するのがいいのかもしれない。（図）。だが、記述の初期の段
階おいては接続インターフェースは絶えず変化するので、最初からそのような記述スタイルで始めるのはあまり得策ではない。 abstract system mixin は接続インターフェー
スがほぼ固定してきてから導入しても遅くはない。

7.7

部品間の競合関係を少なくするには？

setup 時にある２つの部品を同時に指定すると絶対に正しく動かない、という組み合わせがありうる。そのような部品は「競合関係にある」と呼ぶ。 4.4.4節で述べたように、メソッドの役割を宣言することで競合は setup 時に
ある程度自動的に検出できる。
競合を減らすには、以下のことに気をつける。

 メソッドを再定義する時にはできるだけ rede ne methodは使用せず、オリジナルの機能を残した extend methodにする。

 ある機能に関連する abstract method は１つの ab-stract system mixin にできるだけまとめる。同様に、ある機能を実装する implement method や、ある機能を拡張する extend method もそれぞれ sys-

tem mixin にまとめる。これにより system mixin の「役割」がはっきりして、競合の度合が減るのではな
いかと思われる。

7.8

追加部品はどう実装すべきか？

システム全体の骨格がすでにできている段階で、新たな部品を追加実装する場合、少しでも再利用性の高い部品として記述した方が望ましい。再利用性を高くするためには、以下の点が重要である。

 需要が大きく汎用的な機能を提供すること。
 他の部品との組み合わせの自由度が高いこと。（依存する部品および競合する部品の数が少ないこと。）

 長い間安定して使われること。（安定していると思われる接続インターフェースにのみ依存すること。）

17

第 8 章
実装ノート
この章では Ld-2 でのクラスやメソッド呼び出しの実装

8.3.3

方法について簡単に述べる。普通のユーザは、この章を読メソッド呼び出し[o :foo] というメソッド呼び出し形式は、 read macro

む必要はない。

によって (send o :foo) という関数呼び出し形式に展開さ8.1て、関数呼び出し (send-self :foo) を実行する。

れる。関数 send は、特殊変数 *self* の値を o に束縛し実装の概要[:bar] というメソッド呼び出し形式は、 read macro に
よって (send-self :bar) という関数呼び出し形式に展開さLd-2 のシステムはトランスレータと実行時システムからなる。トランスレーターは、 defsystem 構文で定義された system mixin を Common Lisp のプログラムに変換れる。
関数 send-self は、 *self* が属するクラス（構造体 ldclass ）を取り出し、そこからメソッドを検索し実行する。

する。メソッド呼び出しおよびインスタンス変数へのアクセスはハッシュ表を通して行なわれる。 setup 時に各ク
実際には、メソッドキャッシュの処理があるのでもう少ラスが持っているすべてのメソッド探索を探索し、ハッシュ し複雑である。クラスごとに、メソッド名とクロージャの表が構築される。

対応表をハッシュ表として持つ。
現在の実装では、このハッシュ表は、 setup 時に構築

8.2

トランスレーター

される。結局、メソッド呼び出しは１回のハッシュ表検索
ですむことになる。

defsystem 構文は Common Lisp のマクロとして定義されている。入力された system mixin 定義は、図 8.1のようにマクロ展開されてから Common Lisp に解釈され

8.3.4!var というインスタンス変数へのアクセスは、 read macro

る。

8.3
8.3.1

インスタンス変数

によって (send-self :var) に、 (setf !var val) という代入

文は、 (send-self :set-var val) に展開される。

実行時システム

8.3.5

クラス

大域変数

すべての大域変数は、実は <global-variables> というsetup によって system mixin のリストから、個々のクラスが生成される。クラスは、 ld-class という名前の構造体で実現され、 class mixin list を保持する。また、インクラスのインスタンス変数として実現されている。このクラスは、 setup 時に自動的に定義される。起動時にはクラス <global-variables> のインスタンスが１つ生成され、Common Lisp の変数 *global-variables* に代入される。

スタンス変数とメソッドキャッシュを保持し、インスタン（デバッガから (info *global-variables*) と実行してみる

ス生成時およびメソッド呼び出し時に使われる。

とわかる。）

8.3.2

大域変数へのアクセスを行なう !!gvar という式は read

オブジェクトmacro によって [*global-variables* :gvar] を、 (setf!!gvar val) という代入文は [*global-variables* :set-gvar

オブジェクトは、 ld-object という構造体で実現される。この構造体は、 class と variables という２つのスval] を行なう式に展開される。

ロットを持つ。 class は、そのオブジェクトを生成する際将来的に *global-variables* の値が動的に切り替わるに雛型とした ld-class 構造体であり、 variables は、インような言語機能の追加を考えている。

スタンス変数を保持するハッシュ表である。

18

入力：

>(macroexpand'(defsystem <<S>> ()(defclass <super> ()(no-orig)(variable !v)(defmethod :init ()(setf !v 0))(defmethod :add (x)(setf !v (+ !v x))))(defclass <sub> ()(orig <super>)(method :add (x)(print x)[:original x])
)
))

展開結果：

(progn(register-system '<
>(make-system-mixin :name '<
> :classes(list (make-ld-class-mixin :name '<sub> :defp 't :mixin-id'<
>/<sub> :orig '<super> :vars 'nil :methods'((:add <
>/<sub>/add nil)))(make-ld-class-mixin :name '<super> :defp 't :mixin-id'<
>/<super> :orig ':no-orig :vars '(:v) :methods'((:set-v <
>/<super>/set-v t)(:v <
>/<super>/v t) (:add <
>/<super>/add t)(:init <
>/<super>/init t))))))(defun <
>/<sub>/add (x) (print x) (send-self :original x))(defun <
>/<super>/set-v (val)(setf (gethash ':v (ld-object-variables *self*)) val))(defun <
>/<super>/v ()(gethash ':v (ld-object-variables *self*)))(defun <
>/<super>/add (x)(setf (send-self :v) (+ (send-self :v) x)))(defun <
>/<super>/init () (setf (send-self :v) 0)))
図 8.1: defsystem の展開例

19

第 9 章将来の機能拡張

将来、次のような機能拡張を考えている。

 資源名の rename （parameterized module）
 system mixin の repeated inheritance system mixin の依存関係の宣言とエラーチェック（情報隠蔽機能）

 実行効率改善（インライン展開等）
 system mixin の動的な追加・交換

20

参考文献
[1] 一杉裕志、平野聡、田沼均、須崎有康: "無制限に変[13] Lamping, J., Kiczales, G., Rodriguez, L. and Ruf.,
E.: "An Architecture for an Open Compiler", In
更・拡張が可能なコンパイラの設計・実現方法の提案 ",第４８回情報処理学会全国大会, 7G-4, March, 1994.
IMSA: Re ection and Meta-Level Architecture, pp.95106, 1992.
[2] 一杉裕志、平野聡、田沼均、須崎有康、塚本享治: "拡[14] Paakki, J.: "Attribute Grammar Paradigms - A
High-Level Methodology in Language Implemen言語 ", 日本ソフトウエア科学会第１１回大会, pp.29{
tation", ACM Computing Surveys, Vol.27, No.2,
32, 1994.
pp.196{256, June 1995.
[3] 一杉裕志、平野聡、田沼均、須崎有康、塚本享治： "拡[15] Smith, B. C., \Re ection and Semantics in Lisp",
張可能コンパイラキットとその記述言語 ", 第１１回
In Conference Record of ACM POPL '84, pp. 23{
オブジェクト指向計算ワークショップＷＯＯＣ ９５,
35, 1984.
1995.
張可能システムの記述を支援するオブジェクト指向[4] 一杉裕志、平野聡、須崎有康、田沼均、塚本享治: "言 [16] Steele, G.: Common Lisp the Language, 2nd edition , Digital Press (1990).
語処理系クラスライブラリと一体化したオブジェク
ト指向構造エディタ ", 第５１回情報処理学会全国大[17] Szyperski, C.A.: "Import is Not Inheritance, Why
会, 1L-1, September, 1995.
We Need Both: Modules and Classes", In Proc. of
ECOOP'92, pp.19{32, 1995.
[5] 一杉裕志, 平野聡, 田沼均, 須崎有康, 塚本 享治: "コンパイラキット Lods における交換可能なＧＣモジュー [18] Ichisugi, Y.: EPP home page.
ルの構築法 ", プログラミングシンポジウム, Jan, 1997.
http://www.etl.go.jp/~ epp[6] Bodin, F. et al: "Sage++: A Class Library for [19] Gnu Common Lisp
Building Fortran and C++ Restructuring Tools",
ftp://ftp.ma.utexas.edu/pub/gcl/
In Proc. of Object-Oriented Numerics Confs., Oregon, Apr.1994.
[7] Bracha, G. and Cook, W.: "Mixin-based Inheritance", In Proc. of ECOOP/OOPSLA'90, pp.303{
311, 1990.
[8] Chiba, S.: "A Metaobject Protocol for C++", In
Proc. of OOSPLA'95, pp.285{299, 1995.
[9] Gamma, E., H., R., Johnson, R. and Vlissides, J.:
Design Patterns , Addison-Welsley (1995).
[10] Gray,R.W., Heuring,V.P., Levi,S.P., Sloane,A.M.
and Waite,W.M.: "Eli: A Complete, Flexible Compiler Construction System", Communications of
the ACM 35 (February 1992), pp.121{131.
[11] Ishikawa, Y.: "Meta-level Architecture for Extendable C++ Draft Document", Technical Report TR94024, RWCP, 1994.
[12] Kiczales, G., des Rivieres, J. and Bobrow, D. G.:
The Art of Metaobject Protocol, MIT Press, 1991.
21