プログラミング言語における定数とは何か
最近、プログラミング言語において「定数」とは何なのか、を説明する機会がありました。あまり言語化してこなかった部分ということもあり、自分の理解を文字に起こしておきます。
このエントリでは具体例として主にJavaScriptを使用しています。異なる言語では細かい挙動は一致しないことが普通ですので、そこは適宜読み替えてください。また「これが正解だ」ということを主張するものではなく、あくまで私の理解の説明です。そのため技術的に誤っていることを言っていることがあれば、優しく指摘してください。
先に結論
始めに結論から入りましょう。プログラミング言語における「定数」は、次の2項を備えた機能を指します。
- 値に名前を与える
- 再代入不可能
変数 vs 定数
「定数」と対になる概念は「変数」です。どちらも値に名前を与えるという機能は同一ですが、変数は何度でも代入できる。定数は宣言時に一度だけ代入し(初期化)、再代入は不可能という違いがあります[1]。定数は不変の参照を宣言すると言い換えることもできます。JavaScriptでは変数宣言はlet
、定数宣言はconst
を使用しますので、次のようになります。
// 変数
let a = 10;
// ok
a = 20;
// 定数
const b = 10;
// ng
b = 20;
イミュータブル vs ミュータブル
さて話をややこしくするために、値の可変性についても見てみます。普段プログラミングをする際に、どこまで気にしているかはわかりませんが、プログラミング言語では一般的にイミュータブル(不変)な値とミュータブル(可変)な値が存在します[2]。
イミュータブルとは、作成された値を変更できない(状態を変えられない)ということです。JavaScriptでは文字列や数値が該当します。
反対にミュータブルとは、作成された値を変更できる(状態を変えられる)ということです。JavaScriptでは配列やオブジェクトはミュータブルです。
// 変数aが参照している「10」という値の状態は変更できない
let a = 10;
// 変数bが参照している配列の状態は変更できる
let b = [];
b.push(10);
定数は誰だ
上述のそれぞれを組み合わせると次の4パターン作れます。
// イミュータブルな値を参照する変数
let a = 10;
// ミュータブルな値を参照する変数
let b = [10];
// イミュータブルな値を参照する定数
const c = 20;
// ミュータブルな値を参照する定数
const d = [20];
このように変数/定数の概念と、イミュータブル/ミュータブルの概念は直交するものです。上記のうち、const d = [20];
が気になる人もいるでしょうか。「const
で宣言した定数なのに値が変わるのは気持ち悪い」というわけです。しかし、それは気にしなくていいのです。先ほど述べたように、「定数である」ことと「値がミュータブルである」ことは直交するので そういうもの なんです。
d.push()
などで状態を変更するのだとしても、わざわざ宣言をlet
にすることはありません。const
は再代入を禁止するものですが、それによって 型が変更されない ことを保証できます。let
にするとそういったメリットも捨てることになります。
まとめると次の結論になります。参照先の値の不変性は関係ありません。
- 変数を宣言する際はまず
const
を使用する - 再代入が必要な場合
let
を使用する
ミュータブルの値を固定する
プログラミング言語によってはミュータブルの値をイミュータブルに変換する方法が提供されています。ここではJavaScriptでのテクニックを紹介します。
先述したようにJavaScriptの配列とオブジェクトはミュータブルです。しかし、次のようにObject#freeze
を使用すれば 値を固定 できます。
const a = Object.freeze([1, 2, 3]);
// ng
a[0] = 10;
おおむねこの方法はうまくいきますが、多次元配列の場合はだめです。Object#freeze
はトップレベルにしか作用しないためです。
const a = Object.freeze([[1], [2], [3]]);
// ok
a[0][0] = 10;
JavaScriptのスーパーセットであるTypeScriptであれば、この問題もうまく解決できます。次のようにconst
アサーション(as const
)を使用します。
const a = [[1], [2], [3]] as const;
// ng
a[0][0] = 10;
このように値の不変性を考える上で、変数か定数かというのは関係ないわけです。
まとめ
人によって「定数」という言葉の意味する範囲が微妙に異なるケースがあるようです。そうなると話が噛み合いません。しかし、なかなか「定数」の認識合わせなんてしませんね。「なんか話が噛み合わないな?」と感じたら、定義の確認をぜひしてください。
参考URL
- https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/const
- https://typescriptbook.jp/reference/values-types-variables/const-assertion