[346] Re:プログラミング言語を作る
投稿者:mizu
2007/02/20 02:13:25
今回の投稿は、説明の都合上、大分長くなってしまいました。迷惑でしたら、
すいません。
>やってみるとそんなに難しくはないんですよね。実際、今回の企画はそれを
>示そうと思ってはじめました。時間がなくてなかなか思うに任せていませんが。
># そんなに難しくはない、ということを示したいんだから、あっという間に
># 実装できた方が説得力あるんでしょうけどねえ。
簡単に実装するなら、Lisp系言語などが楽でいいのではと思いましたが、
どうでしょうか。普通の言語に比べて、構文がちょっと特殊ですが、機能
拡張がわりと容易ですし、言語設計の面白さは十分に味わうことができるの
ではないかと思います。
>・委譲の言語仕様とか、
基本的なアイデアとしては、いわゆる「単純委譲」をコンパイラが自動生成する
というもので、Java風に書くと、
class MyList{
forward List list_ = new ArrayList();//委譲宣言
}
というコードから、
class MyList{
List list_ = new ArrayList();
public void add(Object o){
list_.add(o);
public Object get(index i){
return list_.get(i);
}
}
というコードをコンパイラが生成します。もちろん、これだけだと
メソッド名が衝突したときに問題が発生しますが、経験から言って、
そのような衝突は、おそらくさほど頻度は高くないだろうと思われるので、
コンパイルエラーにして、衝突したメソッドのみ、プログラマにどのフィールドに
委譲するか(あるいはそもそも委譲せず、そのメソッドを新たに定義するか)を
選択させれば良いと考えています。
あと、全部のメソッドを委譲するだけでは不便なので、委譲したくないメソッドを
列挙する機能も必要かなと考えていますが、これはまだ実装するかどうかわかり
ません。
>・クロージャの実装方法(環境へのアクセス方法)とか、
実は、クロージャの部分はまだ実装できていないのですが、仕様は大体決まって
いて、クロージャは、新たなデータ型を導入するのではなく、インタフェース
の実装クラスのインスタンスとして、クロージャを生成するという方法を
取ろうと思っています。
ActionListener n = #(ActionEvent event){
System.out.println("actionPerformed");
};
というコード(#以降がクロージャの定義で、eventはクロージャの仮引数です)は、
class ActionListener$1 implements ActionListener {
public void actionPerformed(ActionEvent event){
System.out.println("actionPerformed");
}
}
...
ActionListener n = new ActionListener$1();
というコードにコンパイルされます。
ここでは、ActionListenerがメソッドを1つしか持っていないため、クロージャ
の定義では、メソッド名を指定する必要はありませんが、メソッドを複数持った
インタフェースの場合、対応するメソッドを指定する構文を用意しようかと
思っています。
で、問題になっている環境へのアクセス方法ですが、クロージャから外側の
環境にアクセスしていることをコンパイラが検出したら、外側の環境での変数
へのアクセスをObject型配列の要素に対するアクセスに変換して、Object型配列
への参照を、クロージャに渡すという方法を取ります。例えば、
class Hoge{
public static void main(String[] args){
int n = 0;
ActionListener listener = #(ActionEvent event){
n++;
};
listener.actionPerformed(null);
System.out.println("n: " + n);
}
}
というコードは、
class ActionListener$1 implements ActionListener {
private Object[] environment_;
ActionListener(Object[] environment){ environment_ = environment; }
public void actionPerformed(ActionEvent event){
environment_[0] = new Integer(((Integer)environment_[0]).intValue() + 1);
}
}
class Hoge{
public static void main(String[] args){
Object[] environment = new Object[1];
ActionListener listener = new ActionListener$1(environment);
listener.actionPerformed(null);
System.out.println("n: " + ((Integer)environment[0]).intValue());
}
}
というコードにコンパイルされます。このようなクロージャの実装方式は、
クロージャを新たなデータ型として導入するのに比べて、正直使い勝手は
悪いですが、既存のライブラリを活用するという点では、この方式の方が
良いのではないかと思っています。
>・型宣言を省略する方法とか(静的型とのことなので、レキシカルな最初の代入から推測?)
その通りです。例えば、以下の代入があったとして、
n = 1;
代入があった時点でのスコープで、nが宣言されてされていなければ、それは
int n = 1;
という宣言とみなされます。代入される値の型が参照型の場合も、同じですが、
nullが代入される場合だけやや特殊で、
n = null;
は、
Object n = null;
とみなされます。この機能があれば、例えば、よくある
String line;
while((line = reader.readLine()) != null){
..
}
というコードが、変数宣言無しで、
while((line = reader.readLine()) != null){
..
}
だけで書けるようになります(lineのスコープはwhile文で閉じています)。
以上、長々と説明を書かせていただきましたが、よろしければツッコミや
意見をいただければ幸いです。
> 公開される日を楽しみにしています。
どうも有難うございます。頑張って開発を進めたいと思います。