Eclipse Foundationは先日,Xtend 2.4 のリリースを発表した。Xtendは静的型付けを持ったJava風プログラム言語である。記述されたコードはJavaにコンパイルされて,JVM (あるいはAndroidなどJVMライクなシステム) 上で動作する。
ScalaやKotlinといった他のJVMベースのコンパイル言語とは異なり,XtendはJavaコードに変換された後,標準的なJavaコンパイラでコンパイルされる。したがって生成されたコードに下位互換性の問題は存在しない。
さらにGroovyやJRuby/Jythonなどのインタプリタ言語とも異なり,静的型付けでありながら,シンプルなコード記述を可能にする型推測の機能を備えている。これによってリファクタリングや型に依存する補完機能がIDE上で実現されている。
InfoQでは昨年にも 1.0のリリース を伝えているが,その後数多くの変更が行われている。今回リリースされた 2.4の新機能 は,アクティブアノテーション,コレクションリテラル,Androidのサポート,リファクタリングの改善,ツーリングでのコンテントアシストなどだ。
InfoQはXtendのプロジェクトリーダであるSven Efftinge氏に連絡を取り,今回のリリースに関する詳細を聞くことにした。
InfoQ: Xtend 2.4の新機能のひとつとして,アクティブアノテーションが追加されていますが,これがどのようなものなのか,どうやってボイラプレートコードを削減するのかを説明して頂けますか?
Sven Efftinge: 基本的にはアノテーションを記述することによって,その要素をどのようにJavaコード変換するのかをコンパイラに指示する,という方法です。典型的なユースケースはgetterとsetter,observer,visitorなど,一般的なデザインパターンの生成でしょう。ですが,他にもさまざまな使い道がありますから,アクティブアノテーションの開発や配布が手軽にできることを重視しています。
例として,JavaBeanパターンのプロパティを考えてみましょう。これにはget/setメソッドをペアで作る必要があります。いわゆる "Javaコード肥大化" に一役買うわけです。しかしXtendでは,フィールドがプロパティであると宣言するだけで,あとはXtendが処理してくれます。
@Property String nameこれが次のようなJavaコードに変換されます。
private String name; public String getName() { return this.name; } public void setName(String name) { this.name = name; }その他にも,
hashCode()
とequals()
メソッドを自動生成する@Data
や,リリースノート でも紹介したように,データクラスに適用してプロパティ更新リスナのサポートを自動的に追加する@Observable
などのアノテーションがあります。この機能で一番クールなのは,IDEとコンパイラがコード変更を認識してくれることでしょう。タイピングやリンク時はもちろんのこと,ナビゲーションやコンテントアシストといった機能にも変更がオンザフライに反映されて,期待通りの動作をするのです。
コード生成機能はこうあるべきです。
InfoQ: もうひとつの新機能にリテラルコレクションがありますが,配列やセット,マップなどのリテラルはどのように記述するのでしょう?ネストは可能ですか?
Sven Efftinge: ハッシュに続けて中括弧かカギ括弧で記述します。リストの場合は,
val myList = #[1,2,3,4]セットならば,次のように記述します。
val mySet = #{1,2,3}マップはタプル演算子を使って生成します。
val mySet = #{1->"one",2->"two" }配列を記述すべき場所であれば,次のようにリストリテラルを配列リテラルとして使用することもできます。
val int[] myArray = #[1,2,3,4]これらは通常の式ですので,ネストすることももちろん可能です。
InfoQ: リテラルコレクション型はミュータブル(mutable/可変)でしょうか,あるいはイミュータブル(immutable/不変)なのでしょうか?ミュータブルなコレクションをリテラルで初期化することは可能ですか?
Sven Efftinge: イミュータブルです。ミュータブルなインスタンスが必要な場合はファクトリメソッドを使用します。
val myArrayList = newArrayList(1,2,3,4)既存のイミュータブルなリストからの生成も,もちろん可能です。
InfoQ: リテラルと言えば,エクステンションプロバイダとはどのようなものなのでしょう?エクステンションメソッドとはどう違うのでしょうか?
Sven Efftinge: エクステンションプロバイダは,プログラムのスコープ内でエクステンションメソッドを提供するオブジェクトです。例で説明するのが一番よいでしょう。
save(Entity)
というメソッドを持ったDAO(Data Access Object) を考えてみてください。Javaでは次のような記述が必要です。
myDao.save(myEntity)XtendならばDAOオブジェクトをエクステンションプロバイダにすることで,メソッドを最初のパラメータタイプのメンバメソッドとして使用できます。ですから次のように記述できるのです。
myEntity.save()この機能は,C#のエクステンションメソッド (エクステンションとして使用できるのは静的メソッドに限られる) よりも大幅に拡張されています。 エクステンションプロバイダを使用することで,実装内容を簡単に入れ替えることができるのです。
InfoQ: JDK 8にはラムダ式をSAM(Single Access Method)型に変換するコンセプトがありますが,現在のXtendでJava 6やJava 7を使っても同じことが可能でしょうか?
Sven Efftinfe JDK8のラムダは,いわゆる関数インターフェースに変換されるだけのものですから,Xtendでも同じことが可能です。新しい機能は,SAM型とともに抽象クラスも使用可能になったことです。これは "Functional Java" などのフレームワークで多用されている方法です。
XtendならばJDK8を待たずとも,現行のJava 6やJava 7で同じことができますし,実際にはJava 5にも対応しています。
InfoQ: 下位互換性についてはどうでしょう? Xtend 1.0でコンパイル可能だったプログラムは,今回のXtend 2.4でも使用できるのですか?
Sven Efftinge: バイナリ互換性がありますから,Xtend 1.0でコンパイルされたプログラムは,変更や再コンパイルをしなくてもXtend 2.4で動作します。
ソースレベルでも互換性を損なうような変更はありません。ただし,以前のバージョンでは警告されていなかった意味的エラーを強調するように,コンパイラのエラーメッセージなどは改良されています。
Xtendではコンパイル結果とソースの両方のレベルで,互換性を重視しているのです。
InfoQ: XtendのプロジェクトがAndroid用にコンパイル,インストールできるようになったのは,フレームワークとして大きな進歩だと思います。ところで,ScalaやKotlinを使ってAndroidアプリケーションをコンパイルすると,完成したパッケージが何メガバイトも大きくなります。Xtendでコンパイルしたアプリケーションは,Javaで直接コーディングした場合と比べて,平均的にどの程度のサイズ増加があるのでしょう?
Sven Efftinge: XtendはJavaのソースコードにコンパイルされて,それからJavaバイトコードにコンパイルされます。ですから,生成されたバイトコードはAndroidで確実に動作するものになります。さらにXtendでは,独自に巨大なライブラリを持つようなことをしていません。既存のJDKのクラスにエクステンションメソッドを追加するクラスがくつか(40K以下)と,1.3MというサイズのGoogle Guavaがあるだけです。
ですからXtendでは,非常に効率のよいAndroidアプリを開発することができるのです。
InfoQ: プログラム言語の成功指標のひとつに,IDEサポートが充実していることがあります。EclipseのXtendサポートはどの程度改良されているのでしょう?
Sven Efftinge: IDEにはフォーマッタや新しいクイックフィックス,新しいリファクタリング,コンテントアシストの大幅な改良など,さまざまな新機能があります。
コンパイラのパフォーマンスも大きく改善されました。 Xtendでは,IDEを使用した開発作業のワークフロー改善にも力を注いでいます。
他のJDMベース言語とは違って,XtendはJDTに対しても良好に動作します。JDTを置き換えたり,weavingを使用する必要はありません。さらに,プロジェクトのコンパイルには任意のバージョンのJavaコンパイラが使用可能です。プラグインとしてインストールされているバージョンに限定されません。
Xtend 2.4の内容は 2.4リリースノート に記載されている。より詳細な情報については Xtend のホームページを参照してほしい。