成らぬは人の為さぬなりけり

エンジニアライフをエンジョイする為のブログ

Scala2.10の新機能を勉強する その3 ValueClass

前回に引き続き、
Scala2.10の新機能を勉強していきます。

今回のテーマは「ValueClass」です。

環境

ValueClassって?

ありがたい事に公式ドキュメントを日本語訳して頂いているページがあります。
値クラスと汎用トレイト - Scala Documentation

こちらによると、

実行時のオブジェクト割り当てを回避する

と書いてあります。
つまりどういう事なんでしょうか?
オブジェクトの生成を行わない?
???
とりあえず、書いてみようかと思います。

ValueClassを定義する

ValueClassは以下の特徴があります。

  • AnyValを継承する
  • ただひとつのpublicなvalパラメータを持てる
  • 汎用トレイトのみ拡張できる
  • defは定義できるが(上記以外の)val、var,内部trait・class・obejctは定義できない

順番に全部試してみます。

まずは、Double.scalaの3行目。

  • AnyValを継承する
  • ただひとつのpublicなvalパラメータを持てる

次に4〜12行目。

  • defは定義できるが(上記以外の)val、var,内部trait・class・obejctは定義できない

これらを書いてみました。
ここまでで、まずは、ValuClass_01.scalaの4行目は実行できます。
ここまでの状態でValueClass_01をjadってみました。

public final class ValueClass_01
{
    public static class delayedInit.body extends AbstractFunction0
    {

        public final Object apply()
        {
            Predef$.MODULE$.println(BoxesRunTime.boxToInteger(Double$.MODULE$.double$extension(10)));
            return BoxedUnit.UNIT;
        }

        public delayedInit.body(ValueClass_01$ $outer)
        {
        }
    }
…
}

DoubleクラスのAnyValをはずしてコンパイルすると、以下のようになります。

public final class ValueClass_01
{
    public static class delayedInit.body extends AbstractFunction0
    {

        public final Object apply()
        {
            Predef$.MODULE$.println(BoxesRunTime.boxToInteger((new Double(10))._mthdouble()));
            return BoxedUnit.UNIT;
        }

        public delayedInit.body(ValueClass_01$ $outer)
        {
        }
    }
…
}

これを見ると前者は「new Double(10)」していない事がわかります。
「オブジェクト割り当てを回避する」というのはこういう事なんですね。
なるほど。

汎用トレイトを拡張する

汎用トレイト、という言葉を初めて聞きました。
汎用トレイトとは、

  • Anyを拡張する
  • メンバとしてdefを持つ
  • 初期化を一切行わない

というトレイトの事だそうです。

上記の例で言うと、「Hoge」トレイトになります。

汎用トレイトを拡張すると

メモリー割り当てのオーバーヘッドを伴うようにもなる

と書かれています。
では、上記例のValueClass_01をjadってみたいと思います。

public final class ValueClass_01
{
    public static class delayedInit.body extends AbstractFunction0
    {

        public final Object apply()
        {
            Predef$.MODULE$.println(BoxesRunTime.boxToInteger(Double$.MODULE$.double$extension(10)));
            Predef$.MODULE$.println((new Double(10)).hoge());
            return BoxedUnit.UNIT;
        }

        public delayedInit.body(ValueClass_01$ $outer)
        {
        }
    }
…
}

なるほど、「new Double(10)」されていますね。

※補足
上記例の「Ten」クラスですが、
「ただひとつのpublicなval」が「パラメータ」では無いので、
コンパイルエラーになりました。という例です。

Implicit Classと組み合わせてみる

ImplicitClassと組み合わせるとInplicitConversion時にオーバーヘッドなく使えるっぽい。

上記例では、「Triple」の例がこれに該当します。
ちょっとつかれてきたので、jadった結果は割愛しますが、
今までの内容を加味すると、確かにオーバーヘッドなく使えるんだろうな、とおもいます。

次回

次回はValueClassの

  • メモリ割り当てが必要になるとき
  • 制約

について勉強したいと思います。