9 オブジェクト指向言語としてのCurl
CurlはJavaのようなオブジェクト指向機能を持っています。ひとつ、Javaにはできない機能として、Curlでは実装を持った多重継承ができるということがあげられます。
多重継承は、クラスの継承で、複数のクラスを同時に継承することを言います。Javaでは、多重継承を行うために、interfaceという構文を持っています。
多重継承で問題になるのは、それぞれのクラスが同じ基底クラスを持っていたときにどのような振る舞いをするか決めれないことがあるということです。そこでJavaでは、interfaceという実装をもたない特別なクラスを用意することで、多重継承を可能にしています。
ところが、やはり実装をもったクラスを多重継承したい場合というのはあります。Curlでは、共有クラスという仕組みで、同じクラスを継承した複数のクラスを継承できるようにしています。つまり、このように、それぞれAを継承したB1とB2というクラスを、Cというクラスで多重継承しています。
{define-class shared A } {define-class B1 {inherits A} } {define-class B2 {inherits A} } {define-class C {inherits B1, B2} }
Javaでは、classとは別にinterfaceという構文を導入した結果、Javaの勉強がinterfaceの部分でつまづくことが多くなってしまっています。Curlでは、そのような使い分けがないので、すべてクラスとしてすっきりと理解できます。
10 関数型言語としてのCurl
CurlはLispのような関数型言語と言えます。
関数型というからには、関数を値として扱える必要がありますが、Curlでは匿名プロシジャーとして関数を値として扱えます。Curlでは関数はプロシジャーと呼ばれます。
関数を値として扱うというのはどういうことかというと、関数やメソッドを変数に代入したり、引数として渡したり、戻り値として受け取ったりできるということです。
次のようにproc-type型として、匿名プロシジャーを扱う変数を定義できます。
let p:{proc-type {int}:void} = xxx
ここで、匿名プロシジャーとして扱える値xxxは、procを使って次のように書けます。
{proc {n:int}:void {popup-message n} }
もちろん、次のような匿名プロシジャーを受け取るプロシジャーを定義することができます。
{define-proc {loop-proc {num:int p:{proc-type {int}:void}}:void {for x:int=1 to num do {p x} } }
これは、回数とプロシジャーを渡すと、その渡されたプロシジャーを指定した回数だけ呼び出すというプロシジャーです。組み合わせると次のようになります。
{define-proc {loop-proc {num:int p:{proc-type {int}:void}}:void {for x:int=1 to num do {p x} } } {define-proc {loop-proc num:int,p:{proc-type {int}:void}}:void {for x:int=1 to num do {p x} } } {loop-proc 4, {proc {n:int}:void {popup-message n}} }
これで、与えた回数だけ処理を繰り返すという制御構造が実現できたことになります。
Javaでは、クロージャーとして同様の機能が検討されています。一度は導入が確定し、そして導入しないことが確定し、そしてまたクロージャーを導入することが確定するなど、複雑な経緯があります。
匿名プロシジャーやクロージャーのような機能は、GUIプログラムや並列処理でシンプルな記述を行うために欠かせないものです。Javaでは匿名クラスを使って同様の機能を実現できますが、構文として書きにくく、見やすいものとは言えません。Curlでは、最初から匿名プロシジャーが使えます。
11 強力なCurlのマクロ
Lispのような言語と言うとき、関数型が使えるだけではなくマクロも必要になります。もちろん、Curlでもそのような強力なマクロが用意されています。
例えば、次のようなマクロを定義すると、loopという構文が定義できます。
{define-macro public {loop ?n:expression ?v:verbatim} {return {expand-template {for ?={expand-template x} to {?n} do {value ?v} } } } }
このマクロは次のように使えます。
{loop 4 {popup-message "こんにちは"} }
先ほどの匿名プロシジャーと同じような機能を実装していますが、使い方はより簡単になっており、元から言語に備わっていた構文のように使えます。
Curlのマクロはかなり強力で、for文のような制御構造もすべてマクロで実装することができます。ただし、あまりにも強力で仕様も複雑なので、定義する際は注意が必要です。
12 ベターJavaとしてのCurl言語
ほかにも、Curlの変数ではnullを認めないなど、Javaに導入の希望があがっているような構文があります。フィールドへのアクセッサもそのような機能のひとつです。
Javaでは、次のように特別な命名規則のメソッドを定義することで、プロパティが定義されたことにしています。
class Foo{ int value = 0; void setValue(int v){ value = v; } int getValue(){ return v; } }
しかし、これはただ「プロパティが定義されたことにする」だけなので、値の読み書きはメソッドの呼び出しをする必要があります。
Foo f = new Foo(); f.set(5); System.out.println(f.get());
Curlではアクセッサ構文が用意されているので、すっきりとした形で利用ができます。
{define-class Bar field _value:int = 0 {getter {value}:int {return self._value} } {setter {value v:int} set self._value = v } }
このアクセッサは次のように使えます。
{let b:Bar = {Bar}} {set b.value = 5} {popup-message b.value}
Javaに対して、プロパティ構文やクロージャーなどさまざまな要望が出ていた時期がありましたが、そういった要望の多くは、既にJavaと同時期に登場したCurlでは実現していたということになります。
13 まとめ
このように、Curlは、さまざまな書き方を可能にする強力な言語を持っています。もちろん、言語だけでなく、コンポーネントやライブラリもひととおり揃っています。
Javaでプログラムを書くことに不満を持ったら、ちょっとCurlを試してみてはどうでしょうか。