Xtend で C# のオブジェクト初期化子っぽい書き方をしてみる

最近 Xtend を使ってるのでメモ書き。Xtend が何なのかとかの説明は無しです。

2013/01/22 追記:標準のやり方があったので、こっちを参照して下さい。
DoubleArror 演算子 - お だ のスペース

Xtend のドキュメントはこちら
Xtend - Modernized Java
C# のオブジェクト初期化子 はこちら
オブジェクト初期化子とコレクション初期化子 (C# プログラミング ガイド)
こんな感じの構文

var item = new MutableObject() { Id = 1, Name = "ABC", Amount = 5d };

Xtend では @Data アノテーションを使うことで、Imutable なオブジェクト(ValueOject)が出力されます。
Imutable なのでコンストラクタにパラメータを渡す形になるためオブジェクト初期化子は不要なのですが、Mutable なオブジェクトの場合はコンストラクタ初期化子が欲しいなーと。

HogeDriven.xtend

package hogedriven

import java.math.BigDecimal
import org.eclipse.xtext.xbase.lib.Procedures$Procedure1
import org.eclipse.xtext.xbase.lib.util.ToStringHelper

class HogeDriven {
 def static void main(String ...args) {
  var item = new MutableObject()
  item.id = 1
  item.name = "abc"
  item.amount = 5bd
  println(item)
 }
}
class MutableObject {
 @Property int id
 @Property String name
 @Property BigDecimal amount
 override String toString() {
  return new ToStringHelper().toString(this)
 }
}

実行結果はこちら

MutableObject [
  _id = 1
  _name = "abc"
  _amount = 5
]

これがこんな風に書けました。

HogeDriven.xtend

package hogedriven

import java.math.BigDecimal
import org.eclipse.xtext.xbase.lib.Procedures$Procedure1
import org.eclipse.xtext.xbase.lib.util.ToStringHelper
import static extension hogedriven.ObjectExtensions.*

class HogeDriven {
 def static void main(String ...args) {
  println(new MutableObject()._([
   id = 1
   name = "abc"
   amount = 5bd
  ]))
 }
} 
class MutableObject {
 @Property int id
 @Property String name
 @Property BigDecimal amount
 override String toString() {
  return new ToStringHelper().toString(this)
 }
}
class ObjectExtensions {
 def static <T> _(T target, Procedures$Procedure1<T> initialBlock) {
  initialBlock.apply(target)
  target
 }
}

実行結果

MutableObject [
  _id = 1
  _name = "abc"
  _amount = 5
]

オブジェクト初期化子 っぽく書けてますが実際は全然違ってます。
別にコンストラクタでの特別の書き方ではなくて単に T 型のインスタンスと T 型のインスタンスを受け取る Procedure を受け取るメソッド(ここでは、"_" という名前)を new した直後に拡張メソッドで呼び出しているだけです。

Procedure は、ラムダ式で書ける & ラムダ式でのパラメータ変数を省略した場合は、"it" という名前になり*1、"it" はそのブロック内では省略出来るのでオブジェクト初期化子っぽく書けてるだけです。


もっといい方法あるかなー?

*1:Groovy と同じですね