No Programming, No Life

プログラミング関連の話題や雑記

Groovy使いがScalaを書く際の注意点(その1:defに気をつけろ)

このシリーズの一覧はこちら

はじめに

昨日(2011-02-19)に第2回Scala道場に参加してきたわけですが、コーディング最中に一点はまったことがあったのでメモしておく。

はまった点

まずは、ソースコード*1をご覧下さい。

/* DishOrderSheetTest.scala */
package dishs

object DishOrderSheetTest {
    def main(args: Array[String]): Unit = {
        var os: DishOrderSheet = new DishOrderSheet(800) // <- ココ注目!
        var ios: IDishOrderSheet = os.takeOrderSheet
        System.out.println("1:" + ios.getOrderValue)
        os.setOrderId("k.kano_vip")
        System.out.println("2:" + ios.getOrderValue)
    }
}

上記でココ注目!とした部分をはじめ、以下のように書いてしまっていました。

def os = new DishOrderSheet(800)

そうです、defです。Groovyでは変数だろうとメソッドだろうと宣言時はいつでもdef♪ですよね。ところがScalaだとdef関数宣言の時で、変数はvarやvalを使ってね、となっている。
ということで、上記例のようにdefで右辺をクラスをnewするように書いてしまうと、毎回新しいクラスがnewされて返ってきちゃう、言うなれば簡易ファクトリメソッドだ!となってしまうわけですね。
よって、osにアクセスするたびにnewされてしまって、その後の以下の部分でosで保持してたインスタンスに対してsetOrderIdしたかったんですが、期待した動作にならなかったわけです。

os.setOrderId("k.kano_vip")
  1. osにアクセスするとnewされたインスタンスが返ってくる
  2. そのインスタンスにsetOrderIdする

みたいな感じになってしまってたわけですね。

まとめ

Groovy使いはScalaを書くときはdefの使いどころを見極めるべし。

*1:ソースコードは抜粋ですので、完全版は[http://d.hatena.ne.jp/aya_eiya/20110219/1298121073:title=リンク元の方]で先に確認しておくことをお勧めします。