¥chapter{ダイナミック・スタイル}
¥label{dynamic_style}

ダイナミック言語(dynamic language)とは、動的な型付けを特徴としたオブジェクト指向プログラミング言語のことです。PythonやRuby,JavaScriptなど代表的なスクリプティング言語が動的な型付けを採用しているため、スクリプティング言語といえばダイナミック言語という理解をしている人も多い。

Konoha は、これらの常識を裏切って、「静的な型付け」によるスクリプティング言語として設計されています。型は、コンパイル時に全て静的に決定する。ただし、Any} 型と呼ぶ特殊な型を導入することで、ダイナミック言語の動的な振る舞いもあわせて実現しています。本章では、Konoha 言語のダイナミック言語を紹介する。

== Any型: ダック・タイピング}

Konoha は、実行時に型付けを行う特別な型として、Any} 型を導入しています。これは、Object}がクラス階層のトップ(全てのクラスに対するスーパークラス）と呼ばれるのに対し、ボトム（つまり全てのクラスのサブクラス）と概念的に定義できます。

具体的に、Any} 型で宣言された変数は、「どのような型の値でも保持することが可能」になります。この特性は、Object}型と見かけ上、似ています。両者の違いを明らかにするため、まずは比較しながらみていきたい。

次の変数 o, a は、それぞれ文字列(String}型)の値が代入され、型エラーは発生しない。

¥begin{quote}
¥begin{jverbatim}
>>> Object o = "naruto"
>>> Any a = "naruto"
¥end{jverbatim}
¥end{quote}

次に、StringクラスのメソッドindexOf()|を呼び出すことを考える。変数 a|, o|が保持する値は、String} 型なので両者ともindexOf()|メソッドを呼び出すことは可能です。しかし、Object} 型に型付けられた変数 o の方は、型エラーとしてコンパイルされない。

¥begin{quote}
¥begin{jverbatim}
>>> Object o = "naruto"
>>> o.indexOf("r")
- [(shell):2]:(error) You have used an undefined method: Object.indexOf
¥end{jverbatim}
¥end{quote}

一方、Any}型は、全てのクラスのサブクラスであり、String}型のindexOf()|も継承しています。ただし、全てのメソッドを継承したクラスを実装することは不可能であるため、実際に行っていることは、変数 a の型を調べて、正しくa.indexOf()|が呼べるかどうか検査し、それから実行しています。

¥begin{quote}
¥begin{jverbatim}
>>> Any a = "naruto"
>>> o.indexOf("r")
2
¥end{jverbatim}
¥end{quote}

もし引き続き、変数 a に 数値1を代入した場合、今度は Int}型はindexOf()|をもたないため、型エラーをランタイム例外として通知されます。

¥begin{quote}
¥begin{jverbatim}
>>> a = 1
>>> a.indexOf("r")
NoSuchMethod!!: 
¥end{jverbatim}
¥end{quote}

Any}型は、変数値の型によって型エラーを実行するは、

上記の例では、変数 t の参照先がたまたま String 型であり、安全に startsWith() 
を呼び出すことができたが、常に String 型であることは保証されない。 
そこで、Konoha のコンパイラは、次節で詳しく述べるが、any 型で型付 
けされた変数のメソッドをコールするとき、型検査を行うコードを追加する。 
追加された型検査によって、実行中に型エラーを検出し、例外を投げること 
で、クラッシュを防いでいます。 

== ダック・タイピング}

ダイナミック言語は、非常に単純化していってしまえば、全ての変数がAny型で宣言されているといえる。そして、「ダック・タイピング」と呼ばれる極めて特徴的な型付けを可能にしています。

¥begin{quote}
"If it walks like a duck and quacks like a duck, it must be a duck"
（もしもそれがアヒルのように歩き、アヒルのように鳴くのなら、それはアヒルである）
¥end{quote}

Javaを代表とする現在のメインストリームオブジェクト指向プログラミングは、非常にスタティックで非常に厳密な型付けを採用しています。ふたつのクラス間でポリモーフィスムを認めるためには、共通のインターフェース(interface)がクラス宣言と同時に仕様化されてなければならない。

ダック・タイピングは、一方で、インターフェースのようなあらかじめ厳密に定義された共通性の代わりに、同じようなメソッド集合があれば、ポリモーフィックなクラスとして扱うことができるという柔軟さがあります。

Konoha は、Any}型を用いれば、ダック・タイピングを利用したプログラミングも実践できます。

¥begin{quote}
¥begin{jverbatim}
>>> Any a = "naruto"
>>> a.indexOf("r")              // indexOf() があれば、
2
>>> a = ["naruto", "sakura", "kakashi"]
>>> a.indexOf("r")              // それはアヒルだ
-1
¥end{jverbatim}
¥end{quote}

英語は、より正確な言語です。日本語では、アヒルであると断定しているが、英語は"must be"を用い、「ほぼアヒルである」というニュアンスを残しています。ダック・タイピングは、アヒルでないものもアヒルとして間違って解釈してしまう可能性を残しています。

意味論では、同音異義語(synomyms/homonyms)問題と読んでいます。たまたま同じ名前を用いていたが、実は違う意味であっても、コンピュータは意味の違いを自動判定できないことです。

== Any型とデータ変換}


== "Run anytime"コンパイル技術}

スタティック言語は、
コンパイラが型検査を行い、プログラム全体が矛盾がなくなるまで実行できない。
これに対し、ダイナミック言語の生産性の高さは、スクリプトを書いたら
いつでも実行でき、コーディング、テスト、デバッグのループを思考を妨げず、
コンパクトにまわせる点にあります。

しかしこの性質は、ダイナミック言語が実行前に型エラーを検査できない副産物であり、
コンパイラからのエラーや警告のレポートが受けられないため、
ソースコードの品質改善はすべてプログラマの手に文字通り、委ねられています。

Konoha 言語では、スタティック言語・ダイナミック言語の両特性の利点を 
享受するため、コンパイル時に、エラーのレポートを出力しながら、同時に 
いつでも実行できるコード生成を可能にする新しいコンパイラ技術を導入し 
ています。本節では、Konoha ”run anytime”compiler として、その設計を紹 
介する。 

¥begin{quote}
¥begin{jverbatim}
void doMethod() { 
	S1; 
	if(condition) { 
		S2; 
		E1; 
	} 
	S3; 
} 
¥end{jverbatim}
¥end{quote}

図 3: エラー (E1) の検出と Runtime 例外の生成 (S1, S2, E1). 
3.1 コンパイラ・ポリシー 

従来のコンパイラ技術は、「エラーがひとつでも発見されれば、コード生成 
を停止する」ポリシーを採用しているといえる。 
このポリシーは、ソフトウェア開発のリリース時において、ソフトウェア 
品質を強く保証するものであるが、ソフトウェア開発サイクルの全体からみ 
たとき、常に望ましいものとは言えない。実際の開発現場では、自分の書い 
たソースコードをその場で検証したいこともあり、開発者はコンパイルをと 
りあえず通すため、一部をコメントアウトしてコンパイルすることも少なく 
ない。 

Konoha の”run anytime” compiler は、この手作業の部分を自動化し、発 
見したエラーをレポートするのと同時に、それを Runtime 例外に変換してコ 
ンパイルを継続する。問題のある個所を実行すれば、実行はそこで停止する。 
これは、ソフトウェア開発者からみれば、生成されたコードを実行してみ 
るか、それともエラー報告箇所を修正するかは、選択肢が与えられることに 

Runtime 例外の生成 

"Run anytime" コンパイラは、クラッシュを防ぐため、エラー検出箇所よ 
り前のステートメントに Runtime 例外を生成する必要があります。しかし、どこ 
に Runtime 例外を生成するかに関しては、いくつかの選択肢が存在する。 
図 3 は、doMethod() メソッド定義です。今、E1 の箇所でエラーを検出 
したことにします。このとき、Runtime 例外は、S1 から E1 の間のどこに生成 
しても E1 を実行し、クラッシュすることはない。しかし、振る舞いが決定 
しないことは望ましくない。 
我々は、Runtime 例外の生成箇所の選択として、次の 3 つのポリシーを用 
意しています。

== メタオブジェクト}

ダイナミック言語のもう一つの特徴は、実行中にメソッドやフィールド変数を
追加・変更可能な点です。

Konoha は、Java 文法を用いて、クラスを定義することができます。次は、 
Konoha におけるクラスの定義例です。 

¥begin{quote}
¥begin{jverbatim}
>>> class Person { 
... String _name; 
... int _age; 
... Person (String name, int age)
...   _name = name; 
...   _age = age; 
... } 
... String getName() { return _name; } 
... } 
>>> Person p = new Person("naruto", 16); 
>>> p.getName(); 
"naruto" 
¥end{jverbatim}
¥end{quote}

Konoha のクラス定義では、上述の Person クラスの場合、String _name| と 
int _age| 用のフィールドが固定長で用意されます。そのため、クラスが定義さ 
れた後、新しいフィールド変数を追加することはできない。 

しかし、ダイナミック言語では、対話モードなど、実行中に変数を追加した 
い場合も存在する。Konoha では、Prototype クラスという特別なクラスを用 
意して、あらかじめ固定長の空フィールドを実行中に追加しながら利用でき 
るようになっています。ただし、Prototype はいくつかの制約があり、Singleton 
クラスであり、すでに定義されたフィールド変数は、型を変更したり、削除 
することはできない。 

メソッドの動的な追加 

Konoha は、全てのクラスにおいて、メソッドをいつでも追加することが 
できます。 

次の例は、Person クラスに setName() を追加した場合です。すでに、イ 
ンスタンス化されているオブジェクトも新たに追加したメソッドを利用可能 
になります。 

¥begin{quote}
¥begin{jverbatim}
>>> p 
>>> void Person.setName(String name) { 
...   _name = name; 
... } 
>>> p.setName("sasuke"); 
>>> 
¥end{jverbatim}
¥end{quote}

もしメソッドを追加したとき、同一名の既存のメソッドが存在した場合、 
引数や戻り値の型が一致する場合は、(オーバーライド不可能な Final メソッ 
ドであっても) 書き換えることができます。次は、getName() を書き換えた場 
合です。

Konoha は、全てのクラスにおいて、メソッドをいつでも追加することが 
できます。 

次の例は、Person クラスに setName() を追加した場合です。すでに、イ 
ンスタンス化されているオブジェクトも新たに追加したメソッドを利用可能 
になります。 

¥begin{quote}
¥begin{jverbatim}
>>> p 
>>> void Person.setName(String name) { 
... _name = name; 
... } 
>>> p.setName("sasuke"); 
>>> 
¥end{jverbatim}
¥end{quote}
