しらとりのブログ

社会人ひよこプログラマのtil

immutableについて考える

不変(immutable)オブジェクトについて考えを整理する備忘録です。C#を前提にいろいろ考えます。

C#のデータ型についての前提

そもそもC#のデータ型が結構複雑です。値型、参照型、プリミティブ型、組み込み型、複合型、ユーザー定義型、etc。 難しい。。。私はいまだによく分かっていません.。 immutableの説明によくあるstringの例も、string自体が結構特殊なので理解の妨げになっている気がします。C#におけるstringは組み込み型であり、参照型であり、プリミティブ型ではありません。だけどimmutableなので値型のように振る舞うそうです。訳が分かりません。

不変(immutable)とは

constのことではありません。代入式で見ると左辺が不変であるのがconst、右辺が不変であるものがimmutableです。immutableとはキーワードがあるわけではなく。オブジェクトの性質を表します。
例のごとくstringを例にしてみます。

//const このPIは3.14固定。
const double PI = 3.14;
// コンパイルエラー
PI = 3.14159;
// immutableなクラスのstringに文字列リテラルで値をセットする。
string str = "Hello World!";
// 別にstr変数は変更できる;
str = "Hello Underworld!";

インスタンスの中の値が変更できないものがimmutableなオブジェクトということですね。変更できないとは、変更する手段(メソッド)がないと言い換えることもできます。

ここでわかりにくいのが、stringは文字列リテラル(""←これ)で宣言できるとこだと思います。組み込み型の特徴です。ですがやっていることは通常のクラスと一緒です。上記の例だとstrにはデータではなくて参照情報が入っています。こっちは参照型の特徴ですね。

参照情報が入っているのならこれを試したいです。

string str = "Hello World!";
string str2 = str;
str2 = "HELLO WORLD!"
Console.WriteLine(str); // Hello World!"

ここの2行目は参照のコピーなのでstrとstr2の参照先は一緒になります。 ですが注目すべきは3行目で、文字列リテラルの代入は値ではなく参照の代入であることです。str2に入っていたstrの参照はこの時点で削除されています。strの参照先データが変わることはありません。これが一見すると参照型なのに値型のように見える仕組みです。文字列リテラルの代入が参照を作っていることがポイントだと思います。

immutableなオブジェクトとは、参照型かつ参照先データの書き換えができない性質をもったオブジェクトということですね。値をセットできるのは基本的に初期化するときのみということになります。

immutableの特徴

データの書き換えができないということは、オブジェクトの状態が変わらないということです。つまりimmutableなオブジェクトへのアクセスは排他制御が必要ありません。(immutableなオブジェクトが入る変数への排他は必要です。) また、オブジェクトの複製が低コストです。参照のコピーで済むためです。mutableなオブジェクトは参照コピーすると一方の変更がもう一方に影響しますよね。しかし、そもそも変更がされなければ参照コピーでも良いという考えです。

あと、少しわかりにくいですが、immutableオブジェクトは参照情報ではなく参照先データが本質になります。例えば"2つのオブジェクトは同じものか?"を考えるとき、mutableなオブジェクトは"参照情報が等しいか?"で考えますがimmutableなオブジェクトは"参照先データが等しいか?"で考えるべきだということです。身近な例でいうと「stringの比較はeqaulsメソッドで行うべき」は参照先データの比較になっていると思います。こういうのをオブジェクトのアイデンティティと言うらしいです。


immutableを活用するというより、データ型を勉強するときに知っておかないとなーとおもった備忘録でした。