1 はじめに
最近、いろいろなプログラミング言語が注目を集めるようになってきました。
Curlは、リッチクライアントアプリケーション(RIA)の開発ツールですが、その言語は非常に面白い特徴をもっています。今回は、Java言語との比較を交えて、Curl言語がどのような特徴をもった言語か見てみましょう。
2 対象読者
プログラミング言語に興味のある方。いろいろなプログラミング言語を知りたい方。Java言語の知識があると読みやすいと思います。またJava言語に不満のある方には共感していただけるかもしれません。
3 Curlってなんだろう
Curlは、ブラウザのプラグインとして、または独立したデスクトップアプリケーションとして動かすことのできるRIA環境です。PC端末にランタイムをインストールし、Curl言語で書かれたプログラムを実行させることで動作します。Curlの守備範囲はとても広く、実際に長崎県庁で使われているような業務システムから、3Dを駆使したゲームまで、さまざまなアプリケーションを作成することができます。
無償で使える開発環境も提供されているので気軽に試すことができます。ライセンスについて詳しくは公式サイトをご覧ください。
4 Curl言語をひとことで言うと
筆者が人にCurlを説明しようとすると、活舌の悪さもあって「パールって変な言語ですよね」などと言われるのですが、「パール」ではなく「カール」です。Perlも面白い言語ですが、今回はCurlのお話です。それはさておき。
Curl言語を説明するとき『Lispの「丸カッコ()」を「中カッコ{}」にして、計算を普通に書けるようにして、Javaのオブジェクト指向を載せた言語』と言っています。Lispという関数型言語にJavaというオブジェクト指向言語がのっかった、という印象です。実際にはCurlはJavaの登場よりも少し前から開発が始まっているので、Javaのマネをしたというわけではありません。
静的か動的か
また、プログラム言語を説明するとき、静的型付けか動的型付けかということが大切な要素になります。つまりコンパイルのときに型が決まっている必要があるか、実行時に型が解決されるかといったことです。
Curlは、どちらかと言われれば、両方、ということになります。主にコンパイル時に型を決まるようにプログラムを書いていきますが、実行時に型を決めるようにも書けるという、いいとこ取りの言語です。
次のページからは、Curl言語で書かれたプログラムを見ながら具体的な文法を説明します。
5 Curl言語の基本
Curl言語で書いたプログラムは次のようなものになります。
{curl 7.0 applet} {curl-file-attributes character-encoding = "shift-jis"} {define-class public First {method public {triple num:int}:int {return num * 3} } } {do {let f:First = {First}} {for i:int=0 to 5 do {let result:int = {f.triple i}} {if result mod 2==0 then {popup-message result & "偶数"} else {popup-message result & "奇数"} } } }
おそらく、最初の印象は「中カッコだらけ」でしょう。Curlでは文を「{~}」で囲みます。中カッコのことを英語で「Curly bracket」と言いますが、そこから「Curl」と名づけられたということも納得できます。
変数の型指定は、「変数名:型」のようになります。また、中カッコでくくられた式はメソッドとなって、最初の式がメソッド名、2番目以降の式が引数となります。
ここまでをちょっとまとめてみましょう。少し補足もあります。
構文 | Curl | Java |
---|---|---|
文 | {~} | ~; |
型指定 | 要素:型 | 型 要素 |
メソッド | {メソッド名 引数} | メソッド名 (引数) |
構文要素 | {構文 パラメータ いろいろ処理} | 構文 (パラメータ){いろいろ処理} |
コンストラクタ | {クラス名 引数} | new クラス名(引数) |
では、この表を元に、ちょっと先ほどのCurlのソースを機械的に書き直してみましょう。このようになります。
define-class public First{ method public int triple(int num){ return(num * 3); } } do{ let First f = new First(); for(int i =0 to 5) do{ let int result = f.triple(i); if(result mod 2==0) then{ popup-message(result & "偶数"); }else{ popup-message(result & "奇数"); } } }
お!なんだかJavaっぽくなりました!
ちょっと強引な部分はありますが、少し構文のルールを覚えてしまえば、ほとんどJavaと同じようなことができることが分かります。
6 Curlに触ってみよう
それでは、少しCurl言語に触ってみましょう。Curlの開発環境はこちらからダウンロードできます。
開発環境をインストールしたら、Curl言語を試してみましょう。通常、手っ取り早くその言語を試すためには、IDEなど言語に対応した開発環境を立ち上げると思います。でも、Curlを試したいなら、最初にやるべきは、ドキュメントを開くことです。
こう書くと、「ドキュメントを見て概要を最初に把握しておくことが、結果的にはてっとり早い」などと言おうとしてると思われるかもしれません。でもCurlのドキュメントはそうではなく、本当にてっとり早いのです。
例えば、ドキュメントを開いて「基本概念 - 構文 > 基本的な構文」の「コメント」の直前に「例:Unicode エスケープ シーケンスの使用」という例があります。
ここで「実行」ボタンを押すと、サンプルコードとして書いてあることが実行されるのです。
サンプルコードの変更と実行
さらに、ここに次のコードを追加してみましょう。
\n {CommandButton label="こんにちは", {on Action at b:CommandButton do {popup-message "やあ!"} } }
ドキュメント中のサンプルが編集できるというのも驚きですが、もちろんここで編集したコードは、そのまま「実行」ボタンで実行することができます。
ここでは、ボタンを押すとポップアップメッセージが出るように処理を書いているので、「こんにちは」ボタンを押すと「やあ!」とメッセージが表示されます。
このように、Curlでいろいろ試すときには、まず試したいことが書いてあるドキュメントを開いて、そのサンプルコードをそのまま編集して実行するというのがおすすめです。
7 マークアップ言語としてのCurl
Curlドキュメントの説明を見ると、「このドキュメントビュワーはCurlで書かれている」とあります。おそらくですが、このドキュメント自体もCurlで書かれていると思われます。
ドキュメントビュワーをその言語自体で書いている開発環境は多くありますが、その多くは、ドキュメント自体はHTMLなどで書かれています。ですが、Curl言語は、このようなドキュメントを書けるような言語になっています。
例えば、次のように記述して文章を装飾できるようになっています。
ここで、この部分を{bold 太く}記述します。
表示結果は次の通りです。
このように、Curlは文章を装飾するためのマークアップ言語として使うことができます。
8 DSLとしてのCurl
DSLは「ドメイン固有言語」の略で、特定の用途のために使われる言語です。GUIの画面構成や設定の記述など、専用の言語や構文を作ることが多かったのですが、「まるでその構成を記述するための言語であるかのように使える」というのを「ある言語をDSLとして使う」と言います。
先ほど、ボタンを配置するサンプルを実行しました。ボタンを表示する部分を、もう少し複雑にして次のようにしてみましょう。
{VBox halign="center", spacing=3pt, {TextField width=5cm}, {HBox spacing=5pt, {CommandButton label="こんにちは" }, {CommandButton label="こんばんは" } } }
これを実行すると、以下のようにコンポーネントが配置されます。
VBoxはコンポーネントを縦に並べるためのもので、HBoxはコンポーネントを横に並べるためのものだと思ってください。そうすると、幅5cmのTextFieldとHBoxを縦にならべ、そのHBoxの中に「こんにちは」ボタンと「こんばんは」ボタンを横にならべる、という構造になっていることが分かります。これは、Curl言語の標準的な文法を使って実現されていますが、GUIを構築するための言語で記述されているかのように見えます。
このように、CurlはDSLとして使えるような構文になっています。Javaで記述しようとすれば、おそらく次のような手続きとしてのコードになるでしょう。
VBox v = new VBox(); v.setHalign("center"); v.setSpacing(3); TextField t = new TextField(); t.setWidth(5); v.add(t); HBox h = new HBox(); h.setSpacing(5); h.add(new CommandButton("こんにちは"); h.add(new CommandButton("こんばんは"); v.add(h);
もちろんJavaでも、次のように書けるようライブラリを設計することで、DSLに近づけることはできますが、やはり少し無理があります。
new VBox( new TextField(). setWidth(5), new HBox( new CommandButton(). setLabel("こんにちは"), new CommandButton(). setLabel("こんばんは") ).setSpacing(5) ).setHalign("center") .setSpacing(3);
細かいところで、値を指定するときに「cm」や「pt」などの単位を指定できるのも、Curlの面白いところです。さらにCurlでは、ビジュアルデザイナを使って画面をデザインすることが可能です。
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を試してみてはどうでしょうか。