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

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

Scala2.10の新機能を勉強する その4 ValueClass(続編)

前回は、ValueClassの使い方を勉強しました。

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

を次回はやります。と宣言したんですが、
今回は「メモリ割り当てが必要になる場合」のみに絞りたいと思います。
※制約の話はその5とかで、、、

環境

メモリ割り当てが必要になる場合

Valueクラスは

オブジェクト割り当てを回避する

と書いてありましたが、
実は以下のような場合はインスタンス化が必要になります。

  1. 値クラスが別の型として扱われるとき。
  2. 値クラスが配列に代入されるとき。
  3. パターンマッチングなどにおいて、実行時の型検査を行うとき。

それぞれ試してみましょう。

値クラスが別の型として扱われるとき

「値クラスが別の型として扱われるとき」とはつまりどういうことでしょうか?
日本語ドキュメントを見ると、
汎用トレイトを拡張していて、
汎用トレイトの型として扱われるような場合の事のようです。

実際にコード書いて試してみます。

※メソッド名は適当なので、意味は気にしない
こんな感じで、

  • 汎用トレイト(Hoge)として扱うメソッド「nameAsHoge」
  • 値クラス(Foo)として扱うメソッド「nameAsFoo」

を定義してみました。
これをjadってみます。

…
            Predef$.MODULE$.println($outer.nameAsHoge(new Foo(1)));
            Predef$.MODULE$.println($outer.nameAsFoo(1));
…

大分はしょりましたが、「nameAsHoge」はnewされている(インスタンス化されている)ことがわかります。

値クラスが配列に代入されるとき

これは読んで字のごとくですが、
配列だけなのか??と思い、その他のコレクションも試してみました。

比較する為に、インスタンス化されない普通の代入パターンも書いてみました。※6行目
では、これもjadってみます。

…
            $outer.hoge_$eq("aaaa");
            $outer.array_$eq((Hoge[])Array$.MODULE$.apply(Predef$.MODULE$.genericWrapArray(new Hoge[] {
                new Hoge("str")
            }), ClassTag$.MODULE$.apply(valueclass/memory/array/ValueClass_04$Hoge)));
            $outer.list_$eq(List$.MODULE$.apply(Predef$.MODULE$.genericWrapArray(new Hoge[] {
                new Hoge("str")
            })));
            $outer.seq_$eq((Seq)Seq$.MODULE$.apply(Predef$.MODULE$.genericWrapArray(new Hoge[] {
                new Hoge("str")
            })));
            $outer.set_$eq((Set)Predef$.MODULE$.Set().apply(Predef$.MODULE$.genericWrapArray(new Hoge[] {
                new Hoge("str")
            })));
            $outer.map_$eq((Map)Predef$.MODULE$.Map().apply(Predef$.MODULE$.wrapRefArray((Object[])(new Tuple2[] {
                scala.Predef.ArrowAssoc..MODULE$.$minus$greater$extension(Predef$.MODULE$.any2ArrowAssoc(new Hoge("key")), new Hoge("value"))
            }))));
…

最初の行以外は、すべて「new Hoge」されています。

パターンマッチングなどにおいて、実行時の型検査を行うとき

「パターンマッチングなどに」
など?など?!などってなんでしょうね、他に何があるんでしょう。。。
そういう所気になってしまうんですが、
とりあえず、「isInstanceOf」での型検査もやってみました。

比較する為に、型検査をしないパターンも最後に書いてます。
では、これもjadってみます。

String s;
            String s1;
            String s2;
            s = "aaa";
            if(new Hoge(s) == null)
                break MISSING_BLOCK_LABEL_122;
            String x = s;
            Predef$.MODULE$.println(x);
            BoxedUnit boxedunit = BoxedUnit.UNIT;
            $outer.hoge_$eq("bbb");
            if(new Hoge($outer.hoge()) instanceof Hoge)
                Predef$.MODULE$.println($outer.hoge());
            $outer.hoge2_$eq("ccc");
            s2 = $outer.hoge();
            s2;
            s2;
            s1 = "ccc";
            JVM INSTR ifnonnull 102;
               goto _L1 _L2
_L1:
            break MISSING_BLOCK_LABEL_93;
_L2:
            break MISSING_BLOCK_LABEL_102;
            JVM INSTR pop ;
            if(s1 != null)
                break MISSING_BLOCK_LABEL_118;
            break MISSING_BLOCK_LABEL_110;
            s1;
            equals();
            JVM INSTR ifeq 118;
               goto _L3 _L4
_L3:
            break MISSING_BLOCK_LABEL_110;
_L4:
            break MISSING_BLOCK_LABEL_118;
            Predef$.MODULE$.println("match");
…

ちょっと長くなってしまいましたが、「isInstanceOf」もインスタンス化されていますね。
型を検査する場合は、インスタンス化が必要です、ということでしょうか?

まとめ

今回は、メモリ割り当てが必要な場合、について勉強しました。
便利な機能を使う場合は、それがどのような事をしていて、
どういう時に最適化され、どういう時に最適化されないのか、
ということを知っておかないと、使う時気持ち悪いので、
こういう事知っておくのはとても大事な事だと思ってます。
※そんなに詳しく勉強したわけではないですが、、、

次回は、制約についてやりたいと思います。
これもとても大事そう。