プログラミング言語における定数とは何か

プログラミング言語における定数とは何か

Clock Icon2024.12.24

最近、プログラミング言語において「定数」とは何なのか、を説明する機会がありました。あまり言語化してこなかった部分ということもあり、自分の理解を文字に起こしておきます。

このエントリでは具体例として主にJavaScriptを使用しています。異なる言語では細かい挙動は一致しないことが普通ですので、そこは適宜読み替えてください。また「これが正解だ」ということを主張するものではなく、あくまで私の理解の説明です。そのため技術的に誤っていることを言っていることがあれば、優しく指摘してください。

先に結論

始めに結論から入りましょう。プログラミング言語における「定数」は、次の2項を備えた機能を指します。

  1. 値に名前を与える
  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にするとそういったメリットも捨てることになります。

まとめると次の結論になります。参照先の値の不変性は関係ありません。

  1. 変数を宣言する際はまずconstを使用する
  2. 再代入が必要な場合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

脚注
  1. デフォルトで変数の再代入が禁止されているというプログラミング言語もあります。 ↩︎

  2. デフォルトでは値はすべてイミュータブルというプログラミング言語もあります。 ↩︎

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.