「代入」の「箱のメタファー」と「タグのメタファー」
nishio.icon 「代入」の「箱のメタファー」とそれによる不都合と「タグのメタファー」について解説して
GPT5.icon
「代入」の2つのメタファー
1) 箱のメタファー(Box metaphor)
変数=中身を入れる「箱」
代入=箱に値をコピーして入れる
参照するたびに箱を開けて中身(値)を読む
うまく説明できる場面
Cのint x=3;のようなプリミティブ値がスタックに置かれる感覚
値セマンティクス(コピー)前提の説明
不都合・誤解を生む点
1. 共有(エイリアシング)を見落とす
オブジェクトや配列を共有する言語で「箱ごとコピー」と誤解しやすい。
code:python
a = 1,2; b = a # bにも同じリストへの参照
b.append(3)
# 箱メタファーだと「別の箱」のはずが、実際は a も変わる -> 混乱
2. 引数受け渡しの誤解
「値渡し vs 参照渡し」論争を招く。Python/JSは「オブジェクトへの参照値を渡す」= 呼び出し側と同じ対象を触れるのに、箱だと「コピー渡し」に見えやすい。
3. 再代入と変更の混同
再代入:変数が別の対象を指すことに変わる
変更:同じ対象の内部状態を変える
箱だと両者がごっちゃになりやすい。
2) タグ(ラベル)のメタファー(Tag/Label metaphor)
オブジェクト(値の実体)がまず存在していて、変数はその対象に貼る「タグ」
代入=あるタグ名をどの対象に貼るか(束縛するか)を変更
同じ対象にタグは複数貼れる(別名=エイリアス)
変更は「対象が変わる」こと、再代入は「タグの貼り替え」
長所
別名参照・同一性が自然に説明できる
code:python
x = 1,2
y = x # 同じ対象に y という新しいタグを貼った
y.append(3) # 対象自体をいじるので x から見ても変化
x is y # True(同じ対象)
再代入の正体が明確
code:python
y = 9 # y のタグを別の対象に貼り替え。元の対象は x が保持
イミュータブルとミュータブルの区別がクリア
イミュータブル(数・文字列・タプル等):対象の中身は変わらない。変化は常に「新しい対象を作り、タグを貼り替える」
ミュータブル(配列・辞書等):対象をその場で変更できる
GCの直観:どの対象にもタグが貼られていなければ回収対象
どの言語に向くか
Python / JavaScript / Ruby / Java(参照型)などの参照セマンティクス中心の説明に相性◎
Cのプリミティブには箱の直観も依然として有用(必要に応じて併用)
よくある混乱の整理(タグで言い直す)
関数引数
「対象に貼られた新しい仮引数タグが、呼び出し中だけ存在する」。
対象を変更すれば呼び出し元にも反映。仮引数を別対象に貼り替えても呼び出し元のタグはそのまま。
code:python
def f(v):
v.append(0) # 対象を変更 -> 共有に反映
v = 9 # vのタグ貼り替え -> 呼び出し元のタグには無関係
L = 1; f(L) # L -> 1,0
浅いコピー / 深いコピー
タグ比喩だと、浅いコピーは「外側の対象だけ新規、内側は元と同じ対象へのタグを再利用」。深いコピーは「内側も新しい対象を作って貼る」。
code:python
import copy
a = 1],[2
b = copy.copy(a) # 浅い
c = copy.deepcopy(a)
再代入とミューテーションの区別(超重要)
code:javascript
let a = {n:1};
let b = a; // 同じ対象に b タグ
a = {n:2}; // a タグを別対象へ貼り替え(bには影響なし)
b.n = 3; // bが指す“元の対象”を変更(aとは無関係)
使い分けの指針(短縮版)
箱メタ:値コピー前提のプリミティブやC言語の基本型説明に便利
タグメタ:現代言語のオブジェクト/参照・可変性・別名・GCを説明するのに適切(誤解が少ない)
一行まとめ
箱=「変数の中に値が入る」
タグ=「変数は“どの対象に名札を付けているか”」
参照・可変・引数挙動を正しく直観するなら、タグのメタファーが安全です。