Ceylon: 本物の進化なのか、それともありふれた新しい言語なのか

大衆のためのオブジェクト指向の関数型プログラミング

コンピューター・サイエンスにおいてプログラミング言語が歩んできた道には、「次なる大物」になるはずだったものの残骸が散らばっています。ある分野に特化した多くの言語がスクリプティング、あるいは専門のアプリケーションで採用されているのは確かですが、C 言語 (およびその派生言語) と Java 言語の代わりとなるのは至難の業です。その一方、Red Hat の Ceylon はこうしたさまざまな言語の特徴を興味深い形で組み合わせ、よく知られた C スタイルの構文を使用しながらも、関数型の有用な特徴とオブジェクト指向をサポートし、さらに簡潔さに重点を置いています。この記事では、Ceylon について詳しく説明するとともに、この未来の VM 言語がエンタープライズ・ソフトウェア開発のなかでその居場所を見つけることができるかどうかを探ります。更新情報: リスト 7 の fail ブロックについて明確にされました (編集者より)。

M. Tim Jones, Platform Architect, Intel

author photo - M. Tim JonesM. Tim Jones は組み込みソフトウェアのエンジニアであり、『Artificial Intelligence: A Systems Approach』、『GNU/Linux Application Programming』(現在、第 2 版です) や『AI Application Programming』(こちらも現在、第 2 版です)、それに『BSD Sockets Programming from a Multilanguage Perspective』などの著者でもあります。技術的な経歴は静止軌道衛星用のカーネル開発から、組み込みシステム・アーキテクチャーやネットワーク・プロトコル開発まで、広範にわたっています。彼は Intel に勤務していて、コロラド州ロングモン在住です。



2011年 7月 22日

最先端のプログラミング言語の設計には、通常 Linux とオープンソースが関わっているものです。それは、プログラミング言語の開発をサポートするために使用できるツールがあることや、言語の設計に進化を引き起こすプラットフォームのオープンな性質のせいかもしれません。あるいは、オープンソースの技術をベースとする開かれた言語 (GNU Compiler Collection ファミリーや Ruby、Python、Perl など) が、実験的な使用を奨励するという点で優れているという理由も考えられます (そして Ceylon を後押ししている企業が Red Hat であることは言うまでもありません)。理由はともあれ、Linux 開発者は、あまり使われていない過去の言語から最新かつ最先端の言語に至るまで、広範な言語を利用できるようになっています。

Ceylon は Java ではありません

「Ceylon は Java ではありません。Ceylon は Java の影響を大きく受けた新しい言語として、Java のファンであることを公言している人々によって設計されたものです。つまり、Java が近い将来使われなくなるようなことはなく、Java が使われないように追い込もうとしている存在もありません」(Gavin King 氏の言葉)。

それにも関わらず、C/C++、Java、Scala、Ruby、Python、Perl、Erlang、Lua、Scheme、その他さまざまな言語のいずれかを使用する開発者は、ビジネス指向のエンタープライズ・ソフトウェア開発に重点を置いた新しい言語の発表に関心を持たなければならないのでしょうか。多くの場合、その必要はありませんが、この記事では Red Hat によって開発されている Ceylon という言語について探り、この言語が、現在最もよく使われている言語の仲間になり得るかどうかを考えてみましょう。

Ceylon の紹介

Ceylon は、Red Hat で Gavin King 氏が主導している新しいプロジェクトです。King 氏は Java 言語におけるパーシスタンス・ソリューションである Hibernate プロジェクトの発起人であり、(大規模な開発に適した最初の言語の 1 つである) Java 技術のファンですが、この言語には不満な点がいくつもあると言っているそうです (その一例を挙げれば、Generics などの言語の複雑性、性急に設計された曖昧な Standard Edition SDK、使いにくいアノテーション構文、中途半端なブロック構造、XML への依存性などがあります)。

そこで King 氏は、Java 言語と SDK の利点と欠点から学んだ教訓を生かしたとしたら、どのような言語になるか考えました。その質問に彼が出した答えが、Ceylon です。この静的に型付けされた言語は、(JVM で動作することも含め) Java 言語が持つ非常に優れた特徴の一部をそのまま保持する一方、読みやすさと組み込みモジュール方式を改善し、高階関数などの関数型言語の特徴を採り入れています。さらに、Ceylon には C 言語と Smalltalk 言語の特徴も採り入れています。Java 言語と同じように、この新しい言語はビジネス・コンピューティングに重点を置いていますが、他の領域でも柔軟かつ有用に機能します。

Ceylon を「Java キラー」と称している人々も一部にいますが (おそらく、Java 言語の将来を疑問視してのことでしょう)、実際のところ、Ceylon は JVM 上で動作することから、Java に置き換わる言語というよりも、Java 技術の拡張と言えます。JVM を使用して Ceylon の実行をサポートするのは理想的なモデルです。なぜなら、現在 JVM をサポートする多数のアーキテクチャーに (Java と同じように) Ceylon を移植できることを意味するからです。


Ceylon 言語の特徴

現在使用されている言語のほとんどは、単純なカテゴリーにはとらわれず、多種多様なプログラミング・スタイルによる表現が可能ですが、それは、Ceylon にしても同じす。Ceylon は静的型付け言語です (つまり、型チェックはコンパイル時に行われるということです。一方、Lisp などの動的型付け言語では、実行時に型チェックが行われます)。Ceylon は Java 言語と同じくオブジェクト指向言語であるとともに、標準的な C 構文スタイルによる高階関数 (関数を入力または出力として取ることのできる関数) もサポートします。Java 言語では高階関数が直接サポートされることはなく、この点は Java と Ceylon との間の決定的な違いの 1 つとなっています。

その一方で、機能を追加するのではなく、機能を削除することで言語の改善を図る場合もあります。Ceylon では Java 言語の要素を単純化および削除し、単純化したスキームに置き換えています。その一例として、Ceylon では publicprotected、および private キーワードは廃止され、代わりにクラスのどの要素を外部で可視にするかを定義する shared アノテーションが採り入れられています。また、オーバーロードの機能も廃止され、より単純な構文でこの機能に代わる方法 (デフォルトを設定したパラメーターや順序付けされたパラメーターなど) を使用できるようにしています。

継承、シーケンス (配列またはリスト構成体)、Generics、名前付き引数などについては、Ceylon でサポートされます。また、実行時の型を管理するための機能も Ceylon に組み込まれています (次のセクションで、この機能の例を検討します)。Ceylon 言語の開発は現在活発に進められている最中で、最終的な機能セットはまだ確定されていません。


Ceylon の具体的な説明

この記事を執筆している時点では、公式に使用できる Ceylon のコンパイラーはまだありませんが、Ceylon 言語の構造は定義されているため、サンプル・アプリケーションを開発して Ceylon の使用方法を探り、その可読性を判断することは可能です。このセクションでは、Ceylon の構造を具体的に説明するサンプル・アプリケーションを見て行きます。

Hello World

ここでは「Hello World」プログラムを例に、単純なテキスト・ストリングをディスプレイに出力する単純なプログラムを作成する方法を説明します。リスト 1 に記載する例に示されている hello という最上位レベルのメソッドは、writeLine メソッドを使用して、ストリングを標準出力に出力します。

リスト 1. Ceylon での Hello World プログラム
doc "Hello World Program"
by "Gavin King"
void hello() {
  writeLine( "Hello World." );
}

API ドキュメント用の (doxygen のようなツールと同様の) アノテーションにも注目してください。このアノテーションによって、メソッドと作成者 (それぞれ doc アノテーション、by アノテーション) を指定することができます。

Ceylon の型

Ceylon には、従来からの型のセットが組み込まれていて、一般クラスとして実装されています。以下に、これらの型を記載します。

  • Natural: 符号なし整数 (ゼロを含む)
  • Integer: 符号付き整数
  • Float: 浮動小数点数
  • Whole: 任意の精度の符号付き整数
  • Decimal: 有効桁数と小数点以下の桁数が任意である 10 進数

デフォルトでは、NaturalInteger、および Float 型は 64 ビットですが、small アノテーションを付けることによって 32 ビットの型として指定することができます。

Ceylon のクラス

Ceylon はオブジェクト指向言語であることから、コードを作成するときにはクラスの概念を使用します。Ceylon でのクラスとは、一連の処理 (メソッド) と状態をカプセル化し、クラスのオブジェクトを初期化するときにその状態をどのように初期化するかについての定義 (コンストラクターと同様のクラス・イニシャライザー) を追加した型のことです。

Ceylon の手法を理解するには、単純なクラスが効果的です。そこで、リスト 2 にカウンター・クラスを表す単純なクラスを記載します。リスト 2 は、オプションの値を指定してクラスを定義します。ユーザーが値を指定しても、しなくてもよいことは、Type? のパターンによって示されます。コンストラクターの代わりにクラス本体に含まれるのはクラス・イニシャライザーです。このコードはプライベート変数 (共有するためのアノテーションを付けない限り、可視にはなりません) を定義し、次に初期化ロジックを定義します。まず、start 変数の有無を調べるところから始まり、この変数が存在すれば、カウントの初期値として使用されます。最初のメソッドには shared アノテーションが付けられるため、クラスの外部に可視になります。インクリメンターを定義するこのメソッドは、呼び出されると単にカウンターをインクリメントするだけのものです。

最後に定義しているのは、現在のカウンター値をユーザーに返すゲッター・メソッドと、カウンターに呼び出し側が指定した値を設定するセッター・メソッドです。ここで注目すべき点は、カウンターの値を設定する変数の属性を作成するために、assign キーワードを使用していることです。このように、コンストラクターを扱う方法が異なるだけでなく (コードはクラス内に埋め込まれます)、デコンストラクターもなければ、複数のコンストラクターを実装する方法もありません (これは、Java 言語との違いの 1 つに過ぎません)。

リスト 2. Ceylon での単純なクラス
01    doc "Simple Counting Class"
02    class Counter( Natural? start ) {
03    
04      doc "Class Initializer"
05      variable Natural count := 0;
06      if (exists start) {
07        count := start;
09      }
10    
11      doc "The incrementer"
12      shared void increment() {
13        count++;
14      }
15    
16      doc "The getter"
17      shared Natural currentValue {
18        return count;
19      }
20
21      doc "The setter"
22      shared assign currentValue {
23        count := currentValue;
24      }
25
26    }

単純なクラスを定義したところで、Ceylon ではこのクラスをどのように使用するのかを見てみましょう。リスト 3 に、Counter クラスを使用するコード・ブロックを記載します。このコードはまず始めにクラスを cnt オブジェクトにインスタンス化します。Ceylon には new キーワードがないことに注目してください。新規 Counter オブジェクトを定義した後は、increment メソッドを呼び出し、続いてゲッター・メソッドを使って Counter 値を取得して、その値を出力します。Ceylon での = 演算子と := 演算子の使い方は異なり、= 指定子は不変の値にだけ使用し、:= 演算子は変数を割り当てるために使用します。

リスト 3. Counter クラスの使用方法
01    Counter cnt = Counter(1);
02    cnt.increment();
03    writeLine( c.currentValue );

Ceylon では、可能な場合には常に不変属性を使用するように奨励しています。不変属性を使用するということは、ある値でいったんオブジェクトが初期化されると、その後でオブジェクトに値が割り当て直される (代入される) ことはないことを意味します。指定の値が可変 (初期化後に変更可能) であることを指定するには、リスト 2 の行 05 に示されているように、variable アノテーションを付けなければなりません。

最後に、Ceylon での制御構造における重要な違いについて言及しておきます。多くの言語では、条件式の後の波括弧 ({}) は、以下のように文が 1 つしかない場合などは省略できることを思い出してください。

if (cnt > 10) statement();

Ceylon ではこの構文を禁止しており、必ず波括弧がなければなりません。つまり、上記のサンプル・コードを Ceylon で作成するとしたら、以下のようになります。

if (cnt > 100) { statement(); }

これは C 言語で最もよくあるエラーの 1 つなので、このような適切なスタイルが要件として追加されているのは歓迎すべきことです。

高階関数

Ceylon には、高階関数と呼ばれる関数型のプログラミング・スタイルが組み込まれています。このことはただ単に、関数がファースト・クラス・オブジェクトとして扱われ、関数へのパラメーターとして関数を使用できるとともに、関数から返す値として関数を指定できることを意味します。King 氏の repeat メソッドの定義に関するプレゼンテーションで使用されていた例を引用すると (リスト 4 を参照)、このメソッドが取る引数は、繰り返しの回数を指定する Natural と、呼び出す関数を指定するメソッド引数の 2 つです。そして repeat メソッド本体の中に for ループを作成し (範囲演算子を使用)、関数パラメーターとして渡されたこのメソッドを呼び出します。

リスト 4. Ceylon での高階関数
01    void repeat( Natural times, void hfunction() ) {
02      for (Natural n in 1..times) {
03        hfunction();
04      }
05    }

このメソッドを使用するのは簡単です。リスト 5 の行 07 に示されているように、使用するのはメソッドの名前だけで、引数は使用しません。

リスト 5. Ceylon での高階関数の使用方法
01    void sayhello() {
02      writeLine( "Hello World." );
03    }
04
05    ...
06
07      repeat( 10, sayhello );

関数型サポートを備えた他の言語とは異なり、Ceylon は匿名関数 (式の中に直接現れ、名前がない関数) をサポートしません。クロージャー (基本的に、別の関数で状態を参照できる関数) のサポートは、Ceylon に組み込まれています。

型縮小

Ceylon には、Java 言語で使われている instanceof 演算子も、C で使われている型キャストも組み込まれていません。代わりに、Ceylon は型縮小 (type narrowing) という機能を実装しており、オブジェクト参照の型のテストと縮小を 1 つのステップで行えるようにしています。その一例として、リスト 6 のコード・セグメントを見てください。このコードは特殊な (is ... ) 構成体を使用して、オブジェクト参照を特定の型に対してテストしています。型が識別されると、型固有のメソッドが使用されます。この構成体は、リスト 2 のオプション・パラメーターで使用されていた (exists ...) 構成体と同様のものです。

リスト 6. Ceylon での型縮小
01    Object obj = <some object>;
02    
03    switch (obj)
04    
05      case (is Counter) {
06        obj.increment();
07      }
08      case (is ComplexCounter) {
09        obj.incrementBy(1);
10      }
11      else {
12        stream.writeLine("Unknown object");
13      }

同じような構成体として、Ceylon には (nonempty ...) として定義される構成体もあります。この構成体をシーケンス (配列またはリスト) に適用すると、シーケンスに要素が含まれていないかどうかを判別することができ、シーケンスに要素が含まれていない場合には、そのシーケンスに対する処理を適用せずに済ませることもできます。

最後に注目する点として、Ceylon での switch 文の構文は、C 言語とも Java 言語とも異なります。C 言語や Jave 言語ではエラーが発生しがちですが、Ceylon はブロック構造を case に適用し、default ケースを使わない代わりに else ブロックを使用します。Ceylon はまた、すべてのインスタンスがカバーされるように、switch 文にインスタンス・テストの完全なリスト、あるいは少なくとも else 節が含まれていることを (コンパイル時に) 確実にします。コンパイラーはこれらの switch 文を自動的にチェックし、カバーされていないインスタンスがある場合にはエラーを生成します。

その他の制御構造

fail または else

ご覧のように、記事の最後にある読者からのコメントでは、Ceylon 言語の機能について議論されています。ここで取り上げている fail ブロックは、ループから抜け出せない場合の処理が行われますが、この fail の代わりに else を使用することで、この else ブロックがループに代わる処理を行う判定ブロックであることがわかるようにすることを検討しています。

Ceylon は従来の if...else 文はもちろんのこと、Java 言語の例外処理機能 (trycatchfinally) も実装しています。さらに Ceylon では、fail ブロックを作成して for ループとともに使用することで、for ループから抜け出せない場合を特定します。一例として、リスト 7 のコードを見てください。

リスト 7. Ceylon の failブロックの例
01 for (Instrument i in instruments) {
02   if (i.failing()) {
03     break;
04   }
05 }
06 fail {
07   // All instruments are working...
08 }

これは、C 言語と Java 言語の両方に共通の設計パターンなので、Ceylon へ追加する価値があります。


Ceylon の将来

King 氏の言葉にあるように、Ceylon はコミュニティーによる取り組みであることから、Ceylon 言語と SDK の設計、構築、検証にはソフトウェア・エンジニアおよびテスターの助けが必要です。この必要性が、Java 言語から Ceylon への移行を支援することを目的とした Java 言語のユーザーからのフィードバックを促すことになったのかもしれません。King 氏は Ceylon の現状について、言語仕様と ANTLR (Another Tool for Language Recognition) 文法が存在していると言っているだけで、今のところはほとんど沈黙を守っています。


さらに詳しく調べてください

新しい言語の必要性を疑う人々も一部にいるかもしれませんが、言語に対するもう 1 つの見方は、問題を解決するために利用できるツール・セットとして捉えることです。すべての言語が問題の解決に適した理想的な言語というわけではありませんが、一部の言語は、特定のソリューション分野にかなり役立ちます。したがって、複数の言語を使用できるということは、喜ぶべきことであって、忌むべきことではありません。Ceylon はまだ開発中なので、これが現在よく使用されている言語と同等の地位を得られるかどうかはわかりませんが、この言語には十分興味深い機能が取り込まれています。最終的に姿を表した Ceylon で、これらの機能をさらに詳しく調べてみると面白いでしょう。

参考文献

学ぶために

製品や技術を入手するために

  • ご自分に最適な方法で IBM 製品を評価してください。評価の方法としては、製品の試用版をダウンロードすることも、オンラインで製品を試してみることも、クラウド環境で製品を使用することもできます。また、SOA Sandbox では、数時間でサービス指向アーキテクチャーの実装方法を効率的に学ぶことができます。

議論するために

  • My developerWorks コミュニティーに加わってください。ここでは他の developerWorks ユーザーとのつながりを持てる他、開発者が主導するブログ、フォーラム、グループ、ウィキを調べることができます。

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Linux, Open source
ArticleID=733192
ArticleTitle=Ceylon: 本物の進化なのか、それともありふれた新しい言語なのか
publish-date=07222011