Blog ブログ

何時までも変わらないあなた – immutable クラス

みなさん今日は。プログラマの安藤です。

今回は不変という概念のお話です。
インスタンスが生成されてから、そのオブジェクトの状態が一切変更されないようなクラスを immutable(不変)なクラスといいます。

例えば .Net の System.String このクラスのインスタンスメソッドには呼び出し時のオブジェクトを変更することはありません

  • C# でのとるに足らない例  

これはどういうことかと言うと、文字列中の文字を置換するだけでも、新たな文字列バッファをアロケートするという比較的重い処理が走るわけです。
ゲーム開発する場合、結構な頻度で文字列を更新することがあるのですが、これがパフォーマンスのボトルネックになったりする。

とはいえ、immutable なクラスとして設計する利点もある。
string 型の変数を操作する場合は、 「何らかの演算を施した結果を代入する」というパターンに従うことになります。 String クラスのパラメータを取らないインスタンスメソッドはあたかも単項演算子であるかのようにみなすことができ、2パラメータの static メソッドは2項演算子と同様となります。

  • 演算子としてのメソッド

と、まあこのように String 型の変数は int などの数値型の変数を扱うのと同様に処理することが可能なわけです。もし String が mutable(変更可能)なオブジェクトとして設計されているとかえって面倒臭い。

  • もし String が mutable だったら

それに string が mutable だったら System.Collections.HashTable のキーとして使用できないしね。

さて、このような immutable クラスですが、うまく使うとバグの可能性を減らしたり、パフォーマンスを改善したりできます。

  • ちょっとワザとらしい例

さて、このようなクラスを定義した場合、このクラスの利用者は次のように考えるかもしれません。

ところが実行時には次のように SomeSettings が複数のオブジェクトで共有されてしまうケースがあり得る。

クラスの内部状態を示すオブジェクトの参照を public にする場合には immutable にするのが吉。

さて、C# の場合、このようなケースではわざわざ immutableなオブジェクトとしてクラスを設計しないでも、SomeSetting を struct として定義すれば、値型となって知らないうちに SomeClass の内部実装が変更されるようなことが避けられるのですが、このような設定オブジェクトは往々にして内部的に使用するメモリが大きくなる。そうなると今度は値のコピーのオーバーヘッドが馬鹿にならない。
それに対して immutable なクラスを定義した場合は、参照を共有するだけなので遥かにパフォーマンスが良い。と、まあ immutable なオブジェクトと mutable なオブジェクトの関係は コピーと変更のオーバーヘッドを交換するものと考えることもできるわけです。

mutable immutable
オブジェクトの部分的な変更 遅い
一部を変更したインスタンスを生成し直す
速い
インスタンスフィールドを変更するだけ
オブジェクトのコピー 速い
参照の共有がコピーと等価
遅い
同じ内容のオブジェクトを生成し直す

と、言うわけでパフォーマンスやバグを出しにくいクラス設計を考えた場合、mutable なクラスと immutable なクラスを適切に使い分けることが望ましいといえます。

採用情報
クラウドクリエイティブスタジオではエンジニアの方を募集中です。