先日「関数型まつり2025」にて「成立するElixirの再束縛(再代入)可という選択 - Speaker Deck」という内容で発表させていただいたのですが、関連して、今回、いろいろな言語における値の不変性と変数の不変性について整理したいと思います。
まず、しばしば混同されがちな「値の不変性」と「変数の不変性」の違いについてです。
値の不変性 (Immutable Value) こちらは、一度作成された値(データ)そのものが変更できない性質を指します。不変な値を変更しようとすると、実際には元の値を変更するのではなく、変更内容を反映した新しい値が作成されます。
変数の不変性 (Immutable Variable) これは、一度値を代入された変数に、別の値を再代入できない性質を指します。多くの言語でconst (JavaScript, C++) やfinal (Java) といったキーワードで実現されます。変数が指し示す「参照先」が固定されると考えると分かりやすいでしょう。変数の不変性は「再束縛(再代入)不可」と言い換えることもできます。
具体例:JavaScriptのconst
JavaScriptのconstは変数を不変にしますが、値まで不変にするとは限りません。
// 変数 'user' は不変(再代入不可)const user={name:"Taro",age:30};// エラー: userに別のオブジェクトを再代入しようとしている// user = { name: "Jiro", age: 25 }; // TypeError: Assignment to constant variable.// OK: userが指し示すオブジェクト(値)のプロパティを変更することは可能user.age=31;// user の中身は { name: "Taro", age: 31 } になる
この例では、userという変数の参照先は変わりませんが、その参照先にあるオブジェクトの中身(値)は変更できてしまっています。これが、値の不変性と変数の不変性の違いになります。
各言語での「値の不変性」と「変数の不変性」の取り扱いをまとめた表が下記になります。
| 言語 | 値の不変性 | 変数の不変性 | 備考・特徴 |
|---|---|---|---|
| Elixir | 不変 | 再束縛可 | = は代入ではなくパターンマッチ演算子。再束縛可だがデータは常に不変。 |
| Erlang | 不変 | 再束縛不可 | 単一静的代入 (SSA)。一度束縛すると再束縛はできない。 |
| Ruby | 混在 | 指定可 | 大文字で再束縛不可にできるが警告付きで再束縛可能。すべてがオブジェクトへの参照。 |
| Scala | 混在 | 指定可 | 再束縛不可のval と再束縛可のvar を明確に使い分ける。 |
| Java | 混在 | 指定可 | final は再束縛を禁止。参照先のオブジェクト内部は変更可能。 |
| TypeScript | 混在 | 指定可 | 再束縛不可のconst と再束縛可のlet を明確に使い分ける。 |
| php | 混在 | 指定可 | const は再束縛を禁止。 |
| Python | 混在 | 再束縛可 | 再束縛を禁止する構文はない。大文字の変数名で定数を示す慣習がある。 |
| Go | 混在 | 指定可 | const で宣言できるのはコンパイル時に決定する値のみ。 |
| Rust | 指定可(mut) | 指定可(mut) | 所有権システムが特徴。デフォルトで不変だがmut で値や変数を可変にできる。 |
| Haskell | 不変 | 再束縛不可 | 純粋関数型言語。参照透明性を保つため、値や変数は常に不変。 |
表の内容について、特に特徴的な言語をいくつかピックアップして補足します。
Erlang と Haskell は、値や変数がイミュータブル(不変) で再束縛が不可になっています
この設計は、意図しない値の変更を防ぎ、コードの安全性を高めることを目的としています。Haskell のような純粋関数型言語では、この不変性がプログラムの正しさを保証するための根幹をなしています。
Erlang は、高い並行性と信頼性を実現するために、変数の再束縛を許さない単一静的代入(SSA) を原則としています。
一方、同じ Erlang VM 上で動作する Elixir は、プログラマーの利便性を考慮して再束縛を許容しています。値自体は Erlang 同様にイミュータブルなため、再束縛しても元のデータが変更されることはなく、安全性は保たれています。
これは両言語の設計思想の違いを示す興味深い点です。
Scala のval /var や TypeScript のconst /let は、開発者に変数が不変か可変かの選択を委ねます。
// Scalaの例val x =10// 再束縛できない (Immutable)// x = 20 // エラーvar y =10// 再束縛できる (Mutable)y =20// OK
一般的なベストプラクティスは 「まずval (またはconst) を使い、どうしても必要な場合のみvar (またはlet で再束縛) を使う」 というものです。これにより、変更される可能性がある変数の範囲を最小限に抑え、コードの見通しを良くします。
Rust はデフォルト挙動としては値は不変で変数の再束縛を許可していませんが、値や変数を変更したい場合は、mut というキーワードで「この値や変数は変更を許可します」と明示的に宣言することで可能となります。
let x=5;// イミュータブル (変更不可)// x = 6; // コンパイルエラー!letmut y=5;// ミュータブル (変更可能)y=6;// OKletmut numbers:Vec<i32>=vec![10,20,30];// ミュータブル (変更可能)numbers.push(40);// OK
この設計は、意図しない値の変更を防ぎ、コードの安全性を高めることを目的としています。
Python や Ruby では、変数は常にオブジェクトへの参照であり、再束縛はいつでも自由に行えます。再束縛を禁止するconst のような仕組みは言語レベルでは提供されていません。
# Pythonの例my_list = [1,2,3]# リストオブジェクトの中身を変更 (再代入に近い)my_list.append(4)# 別のリストオブジェクトに再束縛my_list = [10,20]
この柔軟性は書きやすさにつながる一方、どこで変数の値が変わるか追いにくくなる側面もあります。そのため、Python コミュニティでは定数として扱いたい変数名をすべて大文字で書く(例:MAX_CONNECTIONS = 10)という紳士協定(慣習)が生まれました。
「値の不変性」と「変数の不変性」。これらの用語は、プログラミング言語が「状態」と「データ」をどのように扱うかという設計思想に深く関わっています。
近年のプログラミングでは、イミュータビリティを重視する傾向が強まっています。データが不変で再束縛が不可あれば、プログラムの動作が予測しやすくなり、特に並行処理など複雑な状況でのバグを劇的に減らすことができるからです。
ただ、Elixirでは、値がイミュータブル(不変)である一方、変数は再束縛可という一風変わったアプローチを採用しています。これは上記傾向に反し、悪手のようにも見えますが、データが不変であることや、関数型言語でありスコープ等が限定的に機能していることにより、コードの視認性を損なわずに利便性を享受できる、Elixirならではの個性的な設計思想になっています。
Elixirの再束縛可というアプローチに興味を持たれた方は、ぜひ発表スライドやYouTube動画をご視聴いただければ嬉しいです。
また、今回の関数型まつりでは会社ブースも出展していて、当日のレポートが下記になります。よかったらこちらもご覧いただければ。
id:yu_sakana
id:ymgn
id:sudame
id:cw-terry
id:quietsato
id:inagakin
id:kb-tagawa
id:cw-yokoi
id:kentaro-ishida
id:cw-yashiro
id:cw-daisukeyamamoto
id:cw-suetake
id:cw-kentanakae
id:cw-ryunakayama
id:cw-orita
id:cw-michihiro
id:kaz3284
id:cw-arai
id:erin_the_black
id:cw-astrke
id:wakakuma
id:tasuku43
id:cw-taisei
id:z3r05um
id:tadaken3
id:tinpay
id:tan-yuki
id:cw-ogata
id:hanayo04
id:cwhagiwara
id:yamakenji24
id:Satoooooooooooo
id:trackiss
id:tanakakoichi9230
id:diracmax
id:cw_yukimiyawaki
id:louvre2489
id:cw-ussy
id:murasahi
id:kb-atsushikataoka
id:korosukesize
id:cw-makotoikeda
id:cw-kobayashi
id:shinharad
id:cw-yoheihayashi
id:at-aka
id:cw-chiba
id:cw-tanaka
id:cw-masaki
id:cw-hayama引用をストックしました
引用するにはまずログインしてください
引用をストックできませんでした。再度お試しください
限定公開記事のため引用できません。